diff options
| author | Yuan Fu | 2022-06-14 15:59:46 -0700 |
|---|---|---|
| committer | Yuan Fu | 2022-06-14 15:59:46 -0700 |
| commit | 98bfb240818bae14cd87a1ffeb8fae7cb7846e05 (patch) | |
| tree | 16e8ab06875ed54e110cf98ccdbd7e78f15905c6 /src/lread.c | |
| parent | 184d212042ffa5a4f02c92085d9b6e8346d66e99 (diff) | |
| parent | 787c4ad8b0776280305a220d6669c956d9ed8a5d (diff) | |
| download | emacs-98bfb240818bae14cd87a1ffeb8fae7cb7846e05.tar.gz emacs-98bfb240818bae14cd87a1ffeb8fae7cb7846e05.zip | |
Merge remote-tracking branch 'savannah/master' into feature/tree-sitter
Diffstat (limited to 'src/lread.c')
| -rw-r--r-- | src/lread.c | 2219 |
1 files changed, 1211 insertions, 1008 deletions
diff --git a/src/lread.c b/src/lread.c index f1ffdef04e4..dfabe75113e 100644 --- a/src/lread.c +++ b/src/lread.c | |||
| @@ -656,10 +656,6 @@ struct subst | |||
| 656 | static Lisp_Object read_internal_start (Lisp_Object, Lisp_Object, | 656 | static Lisp_Object read_internal_start (Lisp_Object, Lisp_Object, |
| 657 | Lisp_Object, bool); | 657 | Lisp_Object, bool); |
| 658 | static Lisp_Object read0 (Lisp_Object, bool); | 658 | static Lisp_Object read0 (Lisp_Object, bool); |
| 659 | static Lisp_Object read1 (Lisp_Object, int *, bool, bool); | ||
| 660 | |||
| 661 | static Lisp_Object read_list (bool, Lisp_Object, bool); | ||
| 662 | static Lisp_Object read_vector (Lisp_Object, bool, bool); | ||
| 663 | 659 | ||
| 664 | static Lisp_Object substitute_object_recurse (struct subst *, Lisp_Object); | 660 | static Lisp_Object substitute_object_recurse (struct subst *, Lisp_Object); |
| 665 | static void substitute_in_interval (INTERVAL, void *); | 661 | static void substitute_in_interval (INTERVAL, void *); |
| @@ -940,7 +936,7 @@ lisp_file_lexically_bound_p (Lisp_Object readcharfun) | |||
| 940 | ch = READCHAR; | 936 | ch = READCHAR; |
| 941 | if (ch == '\n') ch = READCHAR; | 937 | if (ch == '\n') ch = READCHAR; |
| 942 | /* It is OK to leave the position after a #! line, since | 938 | /* It is OK to leave the position after a #! line, since |
| 943 | that is what read1 does. */ | 939 | that is what read0 does. */ |
| 944 | } | 940 | } |
| 945 | 941 | ||
| 946 | if (ch != ';') | 942 | if (ch != ';') |
| @@ -1248,10 +1244,9 @@ Return t if the file exists and loads successfully. */) | |||
| 1248 | CHECK_STRING (file); | 1244 | CHECK_STRING (file); |
| 1249 | 1245 | ||
| 1250 | /* If file name is magic, call the handler. */ | 1246 | /* If file name is magic, call the handler. */ |
| 1251 | /* This shouldn't be necessary any more now that `openp' handles it right. | 1247 | handler = Ffind_file_name_handler (file, Qload); |
| 1252 | handler = Ffind_file_name_handler (file, Qload); | 1248 | if (!NILP (handler)) |
| 1253 | if (!NILP (handler)) | 1249 | return call5 (handler, Qload, file, noerror, nomessage, nosuffix); |
| 1254 | return call5 (handler, Qload, file, noerror, nomessage, nosuffix); */ | ||
| 1255 | 1250 | ||
| 1256 | /* The presence of this call is the result of a historical accident: | 1251 | /* The presence of this call is the result of a historical accident: |
| 1257 | it used to be in every file-operation and when it got removed | 1252 | it used to be in every file-operation and when it got removed |
| @@ -2221,7 +2216,7 @@ readevalloop (Lisp_Object readcharfun, | |||
| 2221 | lexical environment, otherwise, turn off lexical binding. */ | 2216 | lexical environment, otherwise, turn off lexical binding. */ |
| 2222 | lex_bound = find_symbol_value (Qlexical_binding); | 2217 | lex_bound = find_symbol_value (Qlexical_binding); |
| 2223 | specbind (Qinternal_interpreter_environment, | 2218 | specbind (Qinternal_interpreter_environment, |
| 2224 | (NILP (lex_bound) || EQ (lex_bound, Qunbound) | 2219 | (NILP (lex_bound) || BASE_EQ (lex_bound, Qunbound) |
| 2225 | ? Qnil : list1 (Qt))); | 2220 | ? Qnil : list1 (Qt))); |
| 2226 | specbind (Qmacroexp__dynvars, Vmacroexp__dynvars); | 2221 | specbind (Qmacroexp__dynvars, Vmacroexp__dynvars); |
| 2227 | 2222 | ||
| @@ -2286,6 +2281,7 @@ readevalloop (Lisp_Object readcharfun, | |||
| 2286 | if (c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\r' | 2281 | if (c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\r' |
| 2287 | || c == NO_BREAK_SPACE) | 2282 | || c == NO_BREAK_SPACE) |
| 2288 | goto read_next; | 2283 | goto read_next; |
| 2284 | UNREAD (c); | ||
| 2289 | 2285 | ||
| 2290 | if (! HASH_TABLE_P (read_objects_map) | 2286 | if (! HASH_TABLE_P (read_objects_map) |
| 2291 | || XHASH_TABLE (read_objects_map)->count) | 2287 | || XHASH_TABLE (read_objects_map)->count) |
| @@ -2300,12 +2296,9 @@ readevalloop (Lisp_Object readcharfun, | |||
| 2300 | DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD, | 2296 | DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD, |
| 2301 | Qnil, false); | 2297 | Qnil, false); |
| 2302 | if (!NILP (Vpurify_flag) && c == '(') | 2298 | if (!NILP (Vpurify_flag) && c == '(') |
| 2303 | { | 2299 | val = read0 (readcharfun, false); |
| 2304 | val = read_list (0, readcharfun, false); | ||
| 2305 | } | ||
| 2306 | else | 2300 | else |
| 2307 | { | 2301 | { |
| 2308 | UNREAD (c); | ||
| 2309 | if (!NILP (readfun)) | 2302 | if (!NILP (readfun)) |
| 2310 | { | 2303 | { |
| 2311 | val = call1 (readfun, readcharfun); | 2304 | val = call1 (readfun, readcharfun); |
| @@ -2349,7 +2342,7 @@ readevalloop (Lisp_Object readcharfun, | |||
| 2349 | { | 2342 | { |
| 2350 | Vvalues = Fcons (val, Vvalues); | 2343 | Vvalues = Fcons (val, Vvalues); |
| 2351 | if (EQ (Vstandard_output, Qt)) | 2344 | if (EQ (Vstandard_output, Qt)) |
| 2352 | Fprin1 (val, Qnil); | 2345 | Fprin1 (val, Qnil, Qnil); |
| 2353 | else | 2346 | else |
| 2354 | Fprint (val, Qnil); | 2347 | Fprint (val, Qnil); |
| 2355 | } | 2348 | } |
| @@ -2582,24 +2575,6 @@ read_internal_start (Lisp_Object stream, Lisp_Object start, Lisp_Object end, | |||
| 2582 | return retval; | 2575 | return retval; |
| 2583 | } | 2576 | } |
| 2584 | 2577 | ||
| 2585 | |||
| 2586 | /* Use this for recursive reads, in contexts where internal tokens | ||
| 2587 | are not allowed. */ | ||
| 2588 | |||
| 2589 | static Lisp_Object | ||
| 2590 | read0 (Lisp_Object readcharfun, bool locate_syms) | ||
| 2591 | { | ||
| 2592 | register Lisp_Object val; | ||
| 2593 | int c; | ||
| 2594 | |||
| 2595 | val = read1 (readcharfun, &c, 0, locate_syms); | ||
| 2596 | if (!c) | ||
| 2597 | return val; | ||
| 2598 | |||
| 2599 | invalid_syntax_lisp (Fmake_string (make_fixnum (1), make_fixnum (c), Qnil), | ||
| 2600 | readcharfun); | ||
| 2601 | } | ||
| 2602 | |||
| 2603 | /* Grow a read buffer BUF that contains OFFSET useful bytes of data, | 2578 | /* Grow a read buffer BUF that contains OFFSET useful bytes of data, |
| 2604 | by at least MAX_MULTIBYTE_LENGTH bytes. Update *BUF_ADDR and | 2579 | by at least MAX_MULTIBYTE_LENGTH bytes. Update *BUF_ADDR and |
| 2605 | *BUF_SIZE accordingly; 0 <= OFFSET <= *BUF_SIZE. If *BUF_ADDR is | 2580 | *BUF_SIZE accordingly; 0 <= OFFSET <= *BUF_SIZE. If *BUF_ADDR is |
| @@ -2658,7 +2633,7 @@ enum { UNICODE_CHARACTER_NAME_LENGTH_BOUND = 200 }; | |||
| 2658 | If the escape sequence forces unibyte, return eight-bit char. */ | 2633 | If the escape sequence forces unibyte, return eight-bit char. */ |
| 2659 | 2634 | ||
| 2660 | static int | 2635 | static int |
| 2661 | read_escape (Lisp_Object readcharfun, bool stringp) | 2636 | read_escape (Lisp_Object readcharfun) |
| 2662 | { | 2637 | { |
| 2663 | int c = READCHAR; | 2638 | int c = READCHAR; |
| 2664 | /* \u allows up to four hex digits, \U up to eight. Default to the | 2639 | /* \u allows up to four hex digits, \U up to eight. Default to the |
| @@ -2688,12 +2663,10 @@ read_escape (Lisp_Object readcharfun, bool stringp) | |||
| 2688 | return '\t'; | 2663 | return '\t'; |
| 2689 | case 'v': | 2664 | case 'v': |
| 2690 | return '\v'; | 2665 | return '\v'; |
| 2666 | |||
| 2691 | case '\n': | 2667 | case '\n': |
| 2692 | return -1; | 2668 | /* ?\LF is an error; it's probably a user mistake. */ |
| 2693 | case ' ': | 2669 | error ("Invalid escape character syntax"); |
| 2694 | if (stringp) | ||
| 2695 | return -1; | ||
| 2696 | return ' '; | ||
| 2697 | 2670 | ||
| 2698 | case 'M': | 2671 | case 'M': |
| 2699 | c = READCHAR; | 2672 | c = READCHAR; |
| @@ -2701,7 +2674,7 @@ read_escape (Lisp_Object readcharfun, bool stringp) | |||
| 2701 | error ("Invalid escape character syntax"); | 2674 | error ("Invalid escape character syntax"); |
| 2702 | c = READCHAR; | 2675 | c = READCHAR; |
| 2703 | if (c == '\\') | 2676 | if (c == '\\') |
| 2704 | c = read_escape (readcharfun, 0); | 2677 | c = read_escape (readcharfun); |
| 2705 | return c | meta_modifier; | 2678 | return c | meta_modifier; |
| 2706 | 2679 | ||
| 2707 | case 'S': | 2680 | case 'S': |
| @@ -2710,7 +2683,7 @@ read_escape (Lisp_Object readcharfun, bool stringp) | |||
| 2710 | error ("Invalid escape character syntax"); | 2683 | error ("Invalid escape character syntax"); |
| 2711 | c = READCHAR; | 2684 | c = READCHAR; |
| 2712 | if (c == '\\') | 2685 | if (c == '\\') |
| 2713 | c = read_escape (readcharfun, 0); | 2686 | c = read_escape (readcharfun); |
| 2714 | return c | shift_modifier; | 2687 | return c | shift_modifier; |
| 2715 | 2688 | ||
| 2716 | case 'H': | 2689 | case 'H': |
| @@ -2719,7 +2692,7 @@ read_escape (Lisp_Object readcharfun, bool stringp) | |||
| 2719 | error ("Invalid escape character syntax"); | 2692 | error ("Invalid escape character syntax"); |
| 2720 | c = READCHAR; | 2693 | c = READCHAR; |
| 2721 | if (c == '\\') | 2694 | if (c == '\\') |
| 2722 | c = read_escape (readcharfun, 0); | 2695 | c = read_escape (readcharfun); |
| 2723 | return c | hyper_modifier; | 2696 | return c | hyper_modifier; |
| 2724 | 2697 | ||
| 2725 | case 'A': | 2698 | case 'A': |
| @@ -2728,19 +2701,19 @@ read_escape (Lisp_Object readcharfun, bool stringp) | |||
| 2728 | error ("Invalid escape character syntax"); | 2701 | error ("Invalid escape character syntax"); |
| 2729 | c = READCHAR; | 2702 | c = READCHAR; |
| 2730 | if (c == '\\') | 2703 | if (c == '\\') |
| 2731 | c = read_escape (readcharfun, 0); | 2704 | c = read_escape (readcharfun); |
| 2732 | return c | alt_modifier; | 2705 | return c | alt_modifier; |
| 2733 | 2706 | ||
| 2734 | case 's': | 2707 | case 's': |
| 2735 | c = READCHAR; | 2708 | c = READCHAR; |
| 2736 | if (stringp || c != '-') | 2709 | if (c != '-') |
| 2737 | { | 2710 | { |
| 2738 | UNREAD (c); | 2711 | UNREAD (c); |
| 2739 | return ' '; | 2712 | return ' '; |
| 2740 | } | 2713 | } |
| 2741 | c = READCHAR; | 2714 | c = READCHAR; |
| 2742 | if (c == '\\') | 2715 | if (c == '\\') |
| 2743 | c = read_escape (readcharfun, 0); | 2716 | c = read_escape (readcharfun); |
| 2744 | return c | super_modifier; | 2717 | return c | super_modifier; |
| 2745 | 2718 | ||
| 2746 | case 'C': | 2719 | case 'C': |
| @@ -2751,7 +2724,7 @@ read_escape (Lisp_Object readcharfun, bool stringp) | |||
| 2751 | case '^': | 2724 | case '^': |
| 2752 | c = READCHAR; | 2725 | c = READCHAR; |
| 2753 | if (c == '\\') | 2726 | if (c == '\\') |
| 2754 | c = read_escape (readcharfun, 0); | 2727 | c = read_escape (readcharfun); |
| 2755 | if ((c & ~CHAR_MODIFIER_MASK) == '?') | 2728 | if ((c & ~CHAR_MODIFIER_MASK) == '?') |
| 2756 | return 0177 | (c & CHAR_MODIFIER_MASK); | 2729 | return 0177 | (c & CHAR_MODIFIER_MASK); |
| 2757 | else if (! ASCII_CHAR_P ((c & ~CHAR_MODIFIER_MASK))) | 2730 | else if (! ASCII_CHAR_P ((c & ~CHAR_MODIFIER_MASK))) |
| @@ -2902,8 +2875,8 @@ read_escape (Lisp_Object readcharfun, bool stringp) | |||
| 2902 | invalid_syntax ("Empty character name", readcharfun); | 2875 | invalid_syntax ("Empty character name", readcharfun); |
| 2903 | name[length] = '\0'; | 2876 | name[length] = '\0'; |
| 2904 | 2877 | ||
| 2905 | /* character_name_to_code can invoke read1, recursively. | 2878 | /* character_name_to_code can invoke read0, recursively. |
| 2906 | This is why read1's buffer is not static. */ | 2879 | This is why read0's buffer is not static. */ |
| 2907 | return character_name_to_code (name, length, readcharfun); | 2880 | return character_name_to_code (name, length, readcharfun); |
| 2908 | } | 2881 | } |
| 2909 | 2882 | ||
| @@ -2932,20 +2905,17 @@ digit_to_number (int character, int base) | |||
| 2932 | return digit < base ? digit : -1; | 2905 | return digit < base ? digit : -1; |
| 2933 | } | 2906 | } |
| 2934 | 2907 | ||
| 2935 | static char const invalid_radix_integer_format[] = "integer, radix %"pI"d"; | 2908 | /* Size of the fixed-size buffer used during reading. |
| 2936 | 2909 | It should be at least big enough for `invalid_radix_integer' but | |
| 2937 | /* Small, as read1 is recursive (Bug#31995). But big enough to hold | 2910 | can usefully be much bigger than that. */ |
| 2938 | the invalid_radix_integer string. */ | 2911 | enum { stackbufsize = 1024 }; |
| 2939 | enum { stackbufsize = max (64, | ||
| 2940 | (sizeof invalid_radix_integer_format | ||
| 2941 | - sizeof "%"pI"d" | ||
| 2942 | + INT_STRLEN_BOUND (EMACS_INT) + 1)) }; | ||
| 2943 | 2912 | ||
| 2944 | static void | 2913 | static void |
| 2945 | invalid_radix_integer (EMACS_INT radix, char stackbuf[VLA_ELEMS (stackbufsize)], | 2914 | invalid_radix_integer (EMACS_INT radix, char stackbuf[VLA_ELEMS (stackbufsize)], |
| 2946 | Lisp_Object readcharfun) | 2915 | Lisp_Object readcharfun) |
| 2947 | { | 2916 | { |
| 2948 | sprintf (stackbuf, invalid_radix_integer_format, radix); | 2917 | int n = snprintf (stackbuf, stackbufsize, "integer, radix %"pI"d", radix); |
| 2918 | eassert (n < stackbufsize); | ||
| 2949 | invalid_syntax (stackbuf, readcharfun); | 2919 | invalid_syntax (stackbuf, readcharfun); |
| 2950 | } | 2920 | } |
| 2951 | 2921 | ||
| @@ -3011,780 +2981,1110 @@ read_integer (Lisp_Object readcharfun, int radix, | |||
| 3011 | *p = '\0'; | 2981 | *p = '\0'; |
| 3012 | return unbind_to (count, string_to_number (read_buffer, radix, NULL)); | 2982 | return unbind_to (count, string_to_number (read_buffer, radix, NULL)); |
| 3013 | } | 2983 | } |
| 2984 | |||
| 3014 | 2985 | ||
| 3015 | /* If the next token is ')' or ']' or '.', we store that character | 2986 | /* Read a character literal (preceded by `?'). */ |
| 3016 | in *PCH and the return value is not interesting. Else, we store | ||
| 3017 | zero in *PCH and we read and return one lisp object. | ||
| 3018 | |||
| 3019 | FIRST_IN_LIST is true if this is the first element of a list. | ||
| 3020 | LOCATE_SYMS true means read symbol occurrences as symbols with | ||
| 3021 | position. */ | ||
| 3022 | |||
| 3023 | static Lisp_Object | 2987 | static Lisp_Object |
| 3024 | read1 (Lisp_Object readcharfun, int *pch, bool first_in_list, bool locate_syms) | 2988 | read_char_literal (Lisp_Object readcharfun) |
| 3025 | { | 2989 | { |
| 3026 | int c; | 2990 | int ch = READCHAR; |
| 3027 | bool uninterned_symbol = false; | 2991 | if (ch < 0) |
| 3028 | bool skip_shorthand = false; | 2992 | end_of_file_error (); |
| 3029 | bool multibyte; | ||
| 3030 | char stackbuf[stackbufsize]; | ||
| 3031 | current_thread->stack_top = stackbuf; | ||
| 3032 | 2993 | ||
| 3033 | *pch = 0; | 2994 | /* Accept `single space' syntax like (list ? x) where the |
| 2995 | whitespace character is SPC or TAB. | ||
| 2996 | Other literal whitespace like NL, CR, and FF are not accepted, | ||
| 2997 | as there are well-established escape sequences for these. */ | ||
| 2998 | if (ch == ' ' || ch == '\t') | ||
| 2999 | return make_fixnum (ch); | ||
| 3034 | 3000 | ||
| 3035 | retry: | 3001 | if ( ch == '(' || ch == ')' || ch == '[' || ch == ']' |
| 3002 | || ch == '"' || ch == ';') | ||
| 3003 | { | ||
| 3004 | CHECK_LIST (Vlread_unescaped_character_literals); | ||
| 3005 | Lisp_Object char_obj = make_fixed_natnum (ch); | ||
| 3006 | if (NILP (Fmemq (char_obj, Vlread_unescaped_character_literals))) | ||
| 3007 | Vlread_unescaped_character_literals = | ||
| 3008 | Fcons (char_obj, Vlread_unescaped_character_literals); | ||
| 3009 | } | ||
| 3036 | 3010 | ||
| 3037 | c = READCHAR_REPORT_MULTIBYTE (&multibyte); | 3011 | if (ch == '\\') |
| 3038 | if (c < 0) | 3012 | ch = read_escape (readcharfun); |
| 3039 | end_of_file_error (); | ||
| 3040 | 3013 | ||
| 3041 | switch (c) | 3014 | int modifiers = ch & CHAR_MODIFIER_MASK; |
| 3042 | { | 3015 | ch &= ~CHAR_MODIFIER_MASK; |
| 3043 | case '(': | 3016 | if (CHAR_BYTE8_P (ch)) |
| 3044 | return read_list (0, readcharfun, locate_syms); | 3017 | ch = CHAR_TO_BYTE8 (ch); |
| 3018 | ch |= modifiers; | ||
| 3045 | 3019 | ||
| 3046 | case '[': | 3020 | int nch = READCHAR; |
| 3047 | return read_vector (readcharfun, 0, locate_syms); | 3021 | UNREAD (nch); |
| 3022 | if (nch <= 32 | ||
| 3023 | || nch == '"' || nch == '\'' || nch == ';' || nch == '(' | ||
| 3024 | || nch == ')' || nch == '[' || nch == ']' || nch == '#' | ||
| 3025 | || nch == '?' || nch == '`' || nch == ',' || nch == '.') | ||
| 3026 | return make_fixnum (ch); | ||
| 3048 | 3027 | ||
| 3049 | case ')': | 3028 | invalid_syntax ("?", readcharfun); |
| 3050 | case ']': | 3029 | } |
| 3051 | { | ||
| 3052 | *pch = c; | ||
| 3053 | return Qnil; | ||
| 3054 | } | ||
| 3055 | 3030 | ||
| 3056 | case '#': | 3031 | /* Read a string literal (preceded by '"'). */ |
| 3057 | c = READCHAR; | 3032 | static Lisp_Object |
| 3058 | if (c == 's') | 3033 | read_string_literal (char stackbuf[VLA_ELEMS (stackbufsize)], |
| 3034 | Lisp_Object readcharfun) | ||
| 3035 | { | ||
| 3036 | char *read_buffer = stackbuf; | ||
| 3037 | ptrdiff_t read_buffer_size = stackbufsize; | ||
| 3038 | specpdl_ref count = SPECPDL_INDEX (); | ||
| 3039 | char *heapbuf = NULL; | ||
| 3040 | char *p = read_buffer; | ||
| 3041 | char *end = read_buffer + read_buffer_size; | ||
| 3042 | /* True if we saw an escape sequence specifying | ||
| 3043 | a multibyte character. */ | ||
| 3044 | bool force_multibyte = false; | ||
| 3045 | /* True if we saw an escape sequence specifying | ||
| 3046 | a single-byte character. */ | ||
| 3047 | bool force_singlebyte = false; | ||
| 3048 | bool cancel = false; | ||
| 3049 | ptrdiff_t nchars = 0; | ||
| 3050 | |||
| 3051 | int ch; | ||
| 3052 | while ((ch = READCHAR) >= 0 && ch != '\"') | ||
| 3053 | { | ||
| 3054 | if (end - p < MAX_MULTIBYTE_LENGTH) | ||
| 3059 | { | 3055 | { |
| 3060 | c = READCHAR; | 3056 | ptrdiff_t offset = p - read_buffer; |
| 3061 | if (c == '(') | 3057 | read_buffer = grow_read_buffer (read_buffer, offset, |
| 3058 | &heapbuf, &read_buffer_size, | ||
| 3059 | count); | ||
| 3060 | p = read_buffer + offset; | ||
| 3061 | end = read_buffer + read_buffer_size; | ||
| 3062 | } | ||
| 3063 | |||
| 3064 | if (ch == '\\') | ||
| 3065 | { | ||
| 3066 | /* First apply string-specific escape rules: */ | ||
| 3067 | ch = READCHAR; | ||
| 3068 | switch (ch) | ||
| 3062 | { | 3069 | { |
| 3063 | /* Accept extended format for hash tables (extensible to | 3070 | case 's': |
| 3064 | other types), e.g. | 3071 | /* `\s' is always a space in strings. */ |
| 3065 | #s(hash-table size 2 test equal data (k1 v1 k2 v2)) */ | 3072 | ch = ' '; |
| 3066 | Lisp_Object tmp = read_list (0, readcharfun, false); | 3073 | break; |
| 3067 | Lisp_Object head = CAR_SAFE (tmp); | 3074 | case ' ': |
| 3068 | Lisp_Object data = Qnil; | 3075 | case '\n': |
| 3069 | Lisp_Object val = Qnil; | 3076 | /* `\SPC' and `\LF' generate no characters at all. */ |
| 3070 | /* The size is 2 * number of allowed keywords to | 3077 | if (p == read_buffer) |
| 3071 | make-hash-table. */ | 3078 | cancel = true; |
| 3072 | Lisp_Object params[12]; | 3079 | continue; |
| 3073 | Lisp_Object ht; | 3080 | default: |
| 3074 | Lisp_Object key = Qnil; | 3081 | UNREAD (ch); |
| 3075 | int param_count = 0; | 3082 | ch = read_escape (readcharfun); |
| 3076 | 3083 | break; | |
| 3077 | if (!EQ (head, Qhash_table)) | 3084 | } |
| 3085 | |||
| 3086 | int modifiers = ch & CHAR_MODIFIER_MASK; | ||
| 3087 | ch &= ~CHAR_MODIFIER_MASK; | ||
| 3088 | |||
| 3089 | if (CHAR_BYTE8_P (ch)) | ||
| 3090 | force_singlebyte = true; | ||
| 3091 | else if (! ASCII_CHAR_P (ch)) | ||
| 3092 | force_multibyte = true; | ||
| 3093 | else /* I.e. ASCII_CHAR_P (ch). */ | ||
| 3094 | { | ||
| 3095 | /* Allow `\C-SPC' and `\^SPC'. This is done here because | ||
| 3096 | the literals ?\C-SPC and ?\^SPC (rather inconsistently) | ||
| 3097 | yield (' ' | CHAR_CTL); see bug#55738. */ | ||
| 3098 | if (modifiers == CHAR_CTL && ch == ' ') | ||
| 3099 | { | ||
| 3100 | ch = 0; | ||
| 3101 | modifiers = 0; | ||
| 3102 | } | ||
| 3103 | if (modifiers & CHAR_SHIFT) | ||
| 3078 | { | 3104 | { |
| 3079 | ptrdiff_t size = XFIXNUM (Flength (tmp)); | 3105 | /* Shift modifier is valid only with [A-Za-z]. */ |
| 3080 | Lisp_Object record = Fmake_record (CAR_SAFE (tmp), | 3106 | if (ch >= 'A' && ch <= 'Z') |
| 3081 | make_fixnum (size - 1), | 3107 | modifiers &= ~CHAR_SHIFT; |
| 3082 | Qnil); | 3108 | else if (ch >= 'a' && ch <= 'z') |
| 3083 | for (int i = 1; i < size; i++) | ||
| 3084 | { | 3109 | { |
| 3085 | tmp = Fcdr (tmp); | 3110 | ch -= ('a' - 'A'); |
| 3086 | ASET (record, i, Fcar (tmp)); | 3111 | modifiers &= ~CHAR_SHIFT; |
| 3087 | } | 3112 | } |
| 3088 | return record; | ||
| 3089 | } | 3113 | } |
| 3090 | 3114 | ||
| 3091 | tmp = CDR_SAFE (tmp); | 3115 | if (modifiers & CHAR_META) |
| 3116 | { | ||
| 3117 | /* Move the meta bit to the right place for a | ||
| 3118 | string. */ | ||
| 3119 | modifiers &= ~CHAR_META; | ||
| 3120 | ch = BYTE8_TO_CHAR (ch | 0x80); | ||
| 3121 | force_singlebyte = true; | ||
| 3122 | } | ||
| 3123 | } | ||
| 3092 | 3124 | ||
| 3093 | /* This is repetitive but fast and simple. */ | 3125 | /* Any modifiers remaining are invalid. */ |
| 3094 | params[param_count] = QCsize; | 3126 | if (modifiers) |
| 3095 | params[param_count + 1] = Fplist_get (tmp, Qsize); | 3127 | invalid_syntax ("Invalid modifier in string", readcharfun); |
| 3096 | if (!NILP (params[param_count + 1])) | 3128 | p += CHAR_STRING (ch, (unsigned char *) p); |
| 3097 | param_count += 2; | 3129 | } |
| 3130 | else | ||
| 3131 | { | ||
| 3132 | p += CHAR_STRING (ch, (unsigned char *) p); | ||
| 3133 | if (CHAR_BYTE8_P (ch)) | ||
| 3134 | force_singlebyte = true; | ||
| 3135 | else if (! ASCII_CHAR_P (ch)) | ||
| 3136 | force_multibyte = true; | ||
| 3137 | } | ||
| 3138 | nchars++; | ||
| 3139 | } | ||
| 3098 | 3140 | ||
| 3099 | params[param_count] = QCtest; | 3141 | if (ch < 0) |
| 3100 | params[param_count + 1] = Fplist_get (tmp, Qtest); | 3142 | end_of_file_error (); |
| 3101 | if (!NILP (params[param_count + 1])) | ||
| 3102 | param_count += 2; | ||
| 3103 | 3143 | ||
| 3104 | params[param_count] = QCweakness; | 3144 | /* If purifying, and string starts with \ newline, |
| 3105 | params[param_count + 1] = Fplist_get (tmp, Qweakness); | 3145 | return zero instead. This is for doc strings |
| 3106 | if (!NILP (params[param_count + 1])) | 3146 | that we are really going to find in etc/DOC.nn.nn. */ |
| 3107 | param_count += 2; | 3147 | if (!NILP (Vpurify_flag) && NILP (Vdoc_file_name) && cancel) |
| 3148 | { | ||
| 3149 | unbind_to (count, Qnil); | ||
| 3150 | return make_fixnum (0); | ||
| 3151 | } | ||
| 3108 | 3152 | ||
| 3109 | params[param_count] = QCrehash_size; | 3153 | if (!force_multibyte && force_singlebyte) |
| 3110 | params[param_count + 1] = Fplist_get (tmp, Qrehash_size); | 3154 | { |
| 3111 | if (!NILP (params[param_count + 1])) | 3155 | /* READ_BUFFER contains raw 8-bit bytes and no multibyte |
| 3112 | param_count += 2; | 3156 | forms. Convert it to unibyte. */ |
| 3157 | nchars = str_as_unibyte ((unsigned char *) read_buffer, | ||
| 3158 | p - read_buffer); | ||
| 3159 | p = read_buffer + nchars; | ||
| 3160 | } | ||
| 3113 | 3161 | ||
| 3114 | params[param_count] = QCrehash_threshold; | 3162 | Lisp_Object obj = make_specified_string (read_buffer, nchars, p - read_buffer, |
| 3115 | params[param_count + 1] = Fplist_get (tmp, Qrehash_threshold); | 3163 | (force_multibyte |
| 3116 | if (!NILP (params[param_count + 1])) | 3164 | || (p - read_buffer != nchars))); |
| 3117 | param_count += 2; | 3165 | return unbind_to (count, obj); |
| 3166 | } | ||
| 3118 | 3167 | ||
| 3119 | params[param_count] = QCpurecopy; | 3168 | /* Make a hash table from the constructor plist. */ |
| 3120 | params[param_count + 1] = Fplist_get (tmp, Qpurecopy); | 3169 | static Lisp_Object |
| 3121 | if (!NILP (params[param_count + 1])) | 3170 | hash_table_from_plist (Lisp_Object plist) |
| 3122 | param_count += 2; | 3171 | { |
| 3172 | Lisp_Object params[12]; | ||
| 3173 | Lisp_Object *par = params; | ||
| 3174 | |||
| 3175 | /* This is repetitive but fast and simple. */ | ||
| 3176 | #define ADDPARAM(name) \ | ||
| 3177 | do { \ | ||
| 3178 | Lisp_Object val = Fplist_get (plist, Q ## name); \ | ||
| 3179 | if (!NILP (val)) \ | ||
| 3180 | { \ | ||
| 3181 | *par++ = QC ## name; \ | ||
| 3182 | *par++ = val; \ | ||
| 3183 | } \ | ||
| 3184 | } while (0) | ||
| 3185 | |||
| 3186 | ADDPARAM (size); | ||
| 3187 | ADDPARAM (test); | ||
| 3188 | ADDPARAM (weakness); | ||
| 3189 | ADDPARAM (rehash_size); | ||
| 3190 | ADDPARAM (rehash_threshold); | ||
| 3191 | ADDPARAM (purecopy); | ||
| 3192 | |||
| 3193 | Lisp_Object data = Fplist_get (plist, Qdata); | ||
| 3194 | |||
| 3195 | /* Now use params to make a new hash table and fill it. */ | ||
| 3196 | Lisp_Object ht = Fmake_hash_table (par - params, params); | ||
| 3197 | |||
| 3198 | Lisp_Object last = data; | ||
| 3199 | FOR_EACH_TAIL_SAFE (data) | ||
| 3200 | { | ||
| 3201 | Lisp_Object key = XCAR (data); | ||
| 3202 | data = XCDR (data); | ||
| 3203 | if (!CONSP (data)) | ||
| 3204 | break; | ||
| 3205 | Lisp_Object val = XCAR (data); | ||
| 3206 | last = XCDR (data); | ||
| 3207 | Fputhash (key, val, ht); | ||
| 3208 | } | ||
| 3209 | if (!NILP (last)) | ||
| 3210 | error ("Hash table data is not a list of even length"); | ||
| 3123 | 3211 | ||
| 3124 | /* This is the hash table data. */ | 3212 | return ht; |
| 3125 | data = Fplist_get (tmp, Qdata); | 3213 | } |
| 3126 | 3214 | ||
| 3127 | /* Now use params to make a new hash table and fill it. */ | 3215 | static Lisp_Object |
| 3128 | ht = Fmake_hash_table (param_count, params); | 3216 | record_from_list (Lisp_Object elems) |
| 3217 | { | ||
| 3218 | ptrdiff_t size = list_length (elems); | ||
| 3219 | Lisp_Object obj = Fmake_record (XCAR (elems), | ||
| 3220 | make_fixnum (size - 1), | ||
| 3221 | Qnil); | ||
| 3222 | Lisp_Object tl = XCDR (elems); | ||
| 3223 | for (int i = 1; i < size; i++) | ||
| 3224 | { | ||
| 3225 | ASET (obj, i, XCAR (tl)); | ||
| 3226 | tl = XCDR (tl); | ||
| 3227 | } | ||
| 3228 | return obj; | ||
| 3229 | } | ||
| 3129 | 3230 | ||
| 3130 | Lisp_Object last = data; | 3231 | /* Turn a reversed list into a vector. */ |
| 3131 | FOR_EACH_TAIL_SAFE (data) | 3232 | static Lisp_Object |
| 3132 | { | 3233 | vector_from_rev_list (Lisp_Object elems) |
| 3133 | key = XCAR (data); | 3234 | { |
| 3134 | data = XCDR (data); | 3235 | ptrdiff_t size = list_length (elems); |
| 3135 | if (!CONSP (data)) | 3236 | Lisp_Object obj = make_nil_vector (size); |
| 3136 | break; | 3237 | Lisp_Object *vec = XVECTOR (obj)->contents; |
| 3137 | val = XCAR (data); | 3238 | for (ptrdiff_t i = size - 1; i >= 0; i--) |
| 3138 | last = XCDR (data); | 3239 | { |
| 3139 | Fputhash (key, val, ht); | 3240 | vec[i] = XCAR (elems); |
| 3140 | } | 3241 | Lisp_Object next = XCDR (elems); |
| 3141 | if (!NILP (last)) | 3242 | free_cons (XCONS (elems)); |
| 3142 | error ("Hash table data is not a list of even length"); | 3243 | elems = next; |
| 3244 | } | ||
| 3245 | return obj; | ||
| 3246 | } | ||
| 3143 | 3247 | ||
| 3144 | return ht; | 3248 | static Lisp_Object |
| 3145 | } | 3249 | bytecode_from_rev_list (Lisp_Object elems, Lisp_Object readcharfun) |
| 3146 | UNREAD (c); | 3250 | { |
| 3147 | invalid_syntax ("#", readcharfun); | 3251 | Lisp_Object obj = vector_from_rev_list (elems); |
| 3148 | } | 3252 | Lisp_Object *vec = XVECTOR (obj)->contents; |
| 3149 | if (c == '^') | 3253 | ptrdiff_t size = ASIZE (obj); |
| 3150 | { | 3254 | |
| 3151 | c = READCHAR; | 3255 | if (!(size >= COMPILED_STACK_DEPTH + 1 && size <= COMPILED_INTERACTIVE + 1 |
| 3152 | if (c == '[') | 3256 | && (FIXNUMP (vec[COMPILED_ARGLIST]) |
| 3153 | { | 3257 | || CONSP (vec[COMPILED_ARGLIST]) |
| 3154 | Lisp_Object tmp; | 3258 | || NILP (vec[COMPILED_ARGLIST])) |
| 3155 | tmp = read_vector (readcharfun, 0, false); | 3259 | && FIXNATP (vec[COMPILED_STACK_DEPTH]))) |
| 3156 | if (ASIZE (tmp) < CHAR_TABLE_STANDARD_SLOTS) | 3260 | invalid_syntax ("Invalid byte-code object", readcharfun); |
| 3157 | error ("Invalid size char-table"); | 3261 | |
| 3158 | XSETPVECTYPE (XVECTOR (tmp), PVEC_CHAR_TABLE); | 3262 | if (load_force_doc_strings |
| 3159 | return tmp; | 3263 | && NILP (vec[COMPILED_CONSTANTS]) |
| 3160 | } | 3264 | && STRINGP (vec[COMPILED_BYTECODE])) |
| 3161 | else if (c == '^') | 3265 | { |
| 3162 | { | 3266 | /* Lazily-loaded bytecode is represented by the constant slot being nil |
| 3163 | c = READCHAR; | 3267 | and the bytecode slot a (lazily loaded) string containing the |
| 3164 | if (c == '[') | 3268 | print representation of (BYTECODE . CONSTANTS). Unpack the |
| 3165 | { | 3269 | pieces by coerceing the string to unibyte and reading the result. */ |
| 3166 | /* Sub char-table can't be read as a regular | 3270 | Lisp_Object enc = vec[COMPILED_BYTECODE]; |
| 3167 | vector because of a two C integer fields. */ | 3271 | Lisp_Object pair = Fread (Fcons (enc, readcharfun)); |
| 3168 | Lisp_Object tbl, tmp = read_list (1, readcharfun, false); | 3272 | if (!CONSP (pair)) |
| 3169 | ptrdiff_t size = list_length (tmp); | 3273 | invalid_syntax ("Invalid byte-code object", readcharfun); |
| 3170 | int i, depth, min_char; | 3274 | |
| 3171 | struct Lisp_Cons *cell; | 3275 | vec[COMPILED_BYTECODE] = XCAR (pair); |
| 3172 | 3276 | vec[COMPILED_CONSTANTS] = XCDR (pair); | |
| 3173 | if (size == 0) | 3277 | } |
| 3174 | error ("Zero-sized sub char-table"); | 3278 | |
| 3175 | 3279 | if (!((STRINGP (vec[COMPILED_BYTECODE]) | |
| 3176 | if (! RANGED_FIXNUMP (1, XCAR (tmp), 3)) | 3280 | && VECTORP (vec[COMPILED_CONSTANTS])) |
| 3177 | error ("Invalid depth in sub char-table"); | 3281 | || CONSP (vec[COMPILED_BYTECODE]))) |
| 3178 | depth = XFIXNUM (XCAR (tmp)); | 3282 | invalid_syntax ("Invalid byte-code object", readcharfun); |
| 3179 | if (chartab_size[depth] != size - 2) | 3283 | |
| 3180 | error ("Invalid size in sub char-table"); | 3284 | if (STRINGP (vec[COMPILED_BYTECODE])) |
| 3181 | cell = XCONS (tmp), tmp = XCDR (tmp), size--; | 3285 | { |
| 3182 | free_cons (cell); | 3286 | if (STRING_MULTIBYTE (vec[COMPILED_BYTECODE])) |
| 3183 | |||
| 3184 | if (! RANGED_FIXNUMP (0, XCAR (tmp), MAX_CHAR)) | ||
| 3185 | error ("Invalid minimum character in sub-char-table"); | ||
| 3186 | min_char = XFIXNUM (XCAR (tmp)); | ||
| 3187 | cell = XCONS (tmp), tmp = XCDR (tmp), size--; | ||
| 3188 | free_cons (cell); | ||
| 3189 | |||
| 3190 | tbl = make_uninit_sub_char_table (depth, min_char); | ||
| 3191 | for (i = 0; i < size; i++) | ||
| 3192 | { | ||
| 3193 | XSUB_CHAR_TABLE (tbl)->contents[i] = XCAR (tmp); | ||
| 3194 | cell = XCONS (tmp), tmp = XCDR (tmp); | ||
| 3195 | free_cons (cell); | ||
| 3196 | } | ||
| 3197 | return tbl; | ||
| 3198 | } | ||
| 3199 | invalid_syntax ("#^^", readcharfun); | ||
| 3200 | } | ||
| 3201 | invalid_syntax ("#^", readcharfun); | ||
| 3202 | } | ||
| 3203 | if (c == '&') | ||
| 3204 | { | 3287 | { |
| 3205 | Lisp_Object length; | 3288 | /* BYTESTR must have been produced by Emacs 20.2 or earlier |
| 3206 | length = read1 (readcharfun, pch, first_in_list, false); | 3289 | because it produced a raw 8-bit string for byte-code and |
| 3207 | c = READCHAR; | 3290 | now such a byte-code string is loaded as multibyte with |
| 3208 | if (c == '"') | 3291 | raw 8-bit characters converted to multibyte form. |
| 3209 | { | 3292 | Convert them back to the original unibyte form. */ |
| 3210 | Lisp_Object tmp, val; | 3293 | vec[COMPILED_BYTECODE] = Fstring_as_unibyte (vec[COMPILED_BYTECODE]); |
| 3211 | EMACS_INT size_in_chars = bool_vector_bytes (XFIXNAT (length)); | ||
| 3212 | unsigned char *data; | ||
| 3213 | |||
| 3214 | UNREAD (c); | ||
| 3215 | tmp = read1 (readcharfun, pch, first_in_list, false); | ||
| 3216 | if (STRING_MULTIBYTE (tmp) | ||
| 3217 | || (size_in_chars != SCHARS (tmp) | ||
| 3218 | /* We used to print 1 char too many | ||
| 3219 | when the number of bits was a multiple of 8. | ||
| 3220 | Accept such input in case it came from an old | ||
| 3221 | version. */ | ||
| 3222 | && ! (XFIXNAT (length) | ||
| 3223 | == (SCHARS (tmp) - 1) * BOOL_VECTOR_BITS_PER_CHAR))) | ||
| 3224 | invalid_syntax ("#&...", readcharfun); | ||
| 3225 | |||
| 3226 | val = make_uninit_bool_vector (XFIXNAT (length)); | ||
| 3227 | data = bool_vector_uchar_data (val); | ||
| 3228 | memcpy (data, SDATA (tmp), size_in_chars); | ||
| 3229 | /* Clear the extraneous bits in the last byte. */ | ||
| 3230 | if (XFIXNUM (length) != size_in_chars * BOOL_VECTOR_BITS_PER_CHAR) | ||
| 3231 | data[size_in_chars - 1] | ||
| 3232 | &= (1 << (XFIXNUM (length) % BOOL_VECTOR_BITS_PER_CHAR)) - 1; | ||
| 3233 | return val; | ||
| 3234 | } | ||
| 3235 | invalid_syntax ("#&...", readcharfun); | ||
| 3236 | } | 3294 | } |
| 3237 | if (c == '[') | 3295 | // Bytecode must be immovable. |
| 3238 | { | 3296 | pin_string (vec[COMPILED_BYTECODE]); |
| 3239 | /* Accept compiled functions at read-time so that we don't have to | 3297 | } |
| 3240 | build them using function calls. */ | ||
| 3241 | Lisp_Object tmp; | ||
| 3242 | struct Lisp_Vector *vec; | ||
| 3243 | tmp = read_vector (readcharfun, 1, false); | ||
| 3244 | vec = XVECTOR (tmp); | ||
| 3245 | if (! (COMPILED_STACK_DEPTH < ASIZE (tmp) | ||
| 3246 | && (FIXNUMP (AREF (tmp, COMPILED_ARGLIST)) | ||
| 3247 | || CONSP (AREF (tmp, COMPILED_ARGLIST)) | ||
| 3248 | || NILP (AREF (tmp, COMPILED_ARGLIST))) | ||
| 3249 | && ((STRINGP (AREF (tmp, COMPILED_BYTECODE)) | ||
| 3250 | && VECTORP (AREF (tmp, COMPILED_CONSTANTS))) | ||
| 3251 | || CONSP (AREF (tmp, COMPILED_BYTECODE))) | ||
| 3252 | && FIXNATP (AREF (tmp, COMPILED_STACK_DEPTH)))) | ||
| 3253 | invalid_syntax ("Invalid byte-code object", readcharfun); | ||
| 3254 | |||
| 3255 | if (STRINGP (AREF (tmp, COMPILED_BYTECODE))) | ||
| 3256 | { | ||
| 3257 | if (STRING_MULTIBYTE (AREF (tmp, COMPILED_BYTECODE))) | ||
| 3258 | { | ||
| 3259 | /* BYTESTR must have been produced by Emacs 20.2 or earlier | ||
| 3260 | because it produced a raw 8-bit string for byte-code and | ||
| 3261 | now such a byte-code string is loaded as multibyte with | ||
| 3262 | raw 8-bit characters converted to multibyte form. | ||
| 3263 | Convert them back to the original unibyte form. */ | ||
| 3264 | ASET (tmp, COMPILED_BYTECODE, | ||
| 3265 | Fstring_as_unibyte (AREF (tmp, COMPILED_BYTECODE))); | ||
| 3266 | } | ||
| 3267 | // Bytecode must be immovable. | ||
| 3268 | pin_string (AREF (tmp, COMPILED_BYTECODE)); | ||
| 3269 | } | ||
| 3270 | 3298 | ||
| 3271 | XSETPVECTYPE (vec, PVEC_COMPILED); | 3299 | XSETPVECTYPE (XVECTOR (obj), PVEC_COMPILED); |
| 3272 | return tmp; | 3300 | return obj; |
| 3273 | } | 3301 | } |
| 3274 | if (c == '(') | ||
| 3275 | { | ||
| 3276 | Lisp_Object tmp; | ||
| 3277 | int ch; | ||
| 3278 | |||
| 3279 | /* Read the string itself. */ | ||
| 3280 | tmp = read1 (readcharfun, &ch, 0, false); | ||
| 3281 | if (ch != 0 || !STRINGP (tmp)) | ||
| 3282 | invalid_syntax ("#", readcharfun); | ||
| 3283 | /* Read the intervals and their properties. */ | ||
| 3284 | while (1) | ||
| 3285 | { | ||
| 3286 | Lisp_Object beg, end, plist; | ||
| 3287 | 3302 | ||
| 3288 | beg = read1 (readcharfun, &ch, 0, false); | 3303 | static Lisp_Object |
| 3289 | end = plist = Qnil; | 3304 | char_table_from_rev_list (Lisp_Object elems, Lisp_Object readcharfun) |
| 3290 | if (ch == ')') | 3305 | { |
| 3291 | break; | 3306 | Lisp_Object obj = vector_from_rev_list (elems); |
| 3292 | if (ch == 0) | 3307 | if (ASIZE (obj) < CHAR_TABLE_STANDARD_SLOTS) |
| 3293 | end = read1 (readcharfun, &ch, 0, false); | 3308 | invalid_syntax ("Invalid size char-table", readcharfun); |
| 3294 | if (ch == 0) | 3309 | XSETPVECTYPE (XVECTOR (obj), PVEC_CHAR_TABLE); |
| 3295 | plist = read1 (readcharfun, &ch, 0, false); | 3310 | return obj; |
| 3296 | if (ch) | ||
| 3297 | invalid_syntax ("Invalid string property list", readcharfun); | ||
| 3298 | Fset_text_properties (beg, end, plist, tmp); | ||
| 3299 | } | ||
| 3300 | 3311 | ||
| 3301 | return tmp; | 3312 | } |
| 3302 | } | ||
| 3303 | 3313 | ||
| 3304 | /* #@NUMBER is used to skip NUMBER following bytes. | 3314 | static Lisp_Object |
| 3305 | That's used in .elc files to skip over doc strings | 3315 | sub_char_table_from_rev_list (Lisp_Object elems, Lisp_Object readcharfun) |
| 3306 | and function definitions. */ | 3316 | { |
| 3307 | if (c == '@') | 3317 | /* A sub-char-table can't be read as a regular vector because of two |
| 3318 | C integer fields. */ | ||
| 3319 | elems = Fnreverse (elems); | ||
| 3320 | ptrdiff_t size = list_length (elems); | ||
| 3321 | if (size < 2) | ||
| 3322 | error ("Invalid size of sub-char-table"); | ||
| 3323 | |||
| 3324 | if (!RANGED_FIXNUMP (1, XCAR (elems), 3)) | ||
| 3325 | error ("Invalid depth in sub-char-table"); | ||
| 3326 | int depth = XFIXNUM (XCAR (elems)); | ||
| 3327 | |||
| 3328 | if (chartab_size[depth] != size - 2) | ||
| 3329 | error ("Invalid size in sub-char-table"); | ||
| 3330 | elems = XCDR (elems); | ||
| 3331 | |||
| 3332 | if (!RANGED_FIXNUMP (0, XCAR (elems), MAX_CHAR)) | ||
| 3333 | error ("Invalid minimum character in sub-char-table"); | ||
| 3334 | int min_char = XFIXNUM (XCAR (elems)); | ||
| 3335 | elems = XCDR (elems); | ||
| 3336 | |||
| 3337 | Lisp_Object tbl = make_uninit_sub_char_table (depth, min_char); | ||
| 3338 | for (int i = 0; i < size - 2; i++) | ||
| 3339 | { | ||
| 3340 | XSUB_CHAR_TABLE (tbl)->contents[i] = XCAR (elems); | ||
| 3341 | elems = XCDR (elems); | ||
| 3342 | } | ||
| 3343 | return tbl; | ||
| 3344 | } | ||
| 3345 | |||
| 3346 | static Lisp_Object | ||
| 3347 | string_props_from_rev_list (Lisp_Object elems, Lisp_Object readcharfun) | ||
| 3348 | { | ||
| 3349 | elems = Fnreverse (elems); | ||
| 3350 | if (NILP (elems) || !STRINGP (XCAR (elems))) | ||
| 3351 | invalid_syntax ("#", readcharfun); | ||
| 3352 | Lisp_Object obj = XCAR (elems); | ||
| 3353 | for (Lisp_Object tl = XCDR (elems); !NILP (tl);) | ||
| 3354 | { | ||
| 3355 | Lisp_Object beg = XCAR (tl); | ||
| 3356 | tl = XCDR (tl); | ||
| 3357 | if (NILP (tl)) | ||
| 3358 | invalid_syntax ("Invalid string property list", readcharfun); | ||
| 3359 | Lisp_Object end = XCAR (tl); | ||
| 3360 | tl = XCDR (tl); | ||
| 3361 | if (NILP (tl)) | ||
| 3362 | invalid_syntax ("Invalid string property list", readcharfun); | ||
| 3363 | Lisp_Object plist = XCAR (tl); | ||
| 3364 | tl = XCDR (tl); | ||
| 3365 | Fset_text_properties (beg, end, plist, obj); | ||
| 3366 | } | ||
| 3367 | return obj; | ||
| 3368 | } | ||
| 3369 | |||
| 3370 | /* Read a bool vector (preceded by "#&"). */ | ||
| 3371 | static Lisp_Object | ||
| 3372 | read_bool_vector (char stackbuf[VLA_ELEMS (stackbufsize)], | ||
| 3373 | Lisp_Object readcharfun) | ||
| 3374 | { | ||
| 3375 | ptrdiff_t length = 0; | ||
| 3376 | for (;;) | ||
| 3377 | { | ||
| 3378 | int c = READCHAR; | ||
| 3379 | if (c < '0' || c > '9') | ||
| 3308 | { | 3380 | { |
| 3309 | enum { extra = 100 }; | 3381 | if (c != '"') |
| 3310 | ptrdiff_t i, nskip = 0, digits = 0; | 3382 | invalid_syntax ("#&", readcharfun); |
| 3383 | break; | ||
| 3384 | } | ||
| 3385 | if (INT_MULTIPLY_WRAPV (length, 10, &length) | ||
| 3386 | | INT_ADD_WRAPV (length, c - '0', &length)) | ||
| 3387 | invalid_syntax ("#&", readcharfun); | ||
| 3388 | } | ||
| 3311 | 3389 | ||
| 3312 | /* Read a decimal integer. */ | 3390 | ptrdiff_t size_in_chars = bool_vector_bytes (length); |
| 3313 | while ((c = READCHAR) >= 0 | 3391 | Lisp_Object str = read_string_literal (stackbuf, readcharfun); |
| 3314 | && c >= '0' && c <= '9') | 3392 | if (STRING_MULTIBYTE (str) |
| 3315 | { | 3393 | || !(size_in_chars == SCHARS (str) |
| 3316 | if ((STRING_BYTES_BOUND - extra) / 10 <= nskip) | 3394 | /* We used to print 1 char too many when the number of bits |
| 3317 | string_overflow (); | 3395 | was a multiple of 8. Accept such input in case it came |
| 3318 | digits++; | 3396 | from an old version. */ |
| 3319 | nskip *= 10; | 3397 | || length == (SCHARS (str) - 1) * BOOL_VECTOR_BITS_PER_CHAR)) |
| 3320 | nskip += c - '0'; | 3398 | invalid_syntax ("#&...", readcharfun); |
| 3321 | if (digits == 2 && nskip == 0) | 3399 | |
| 3322 | { /* We've just seen #@00, which means "skip to end". */ | 3400 | Lisp_Object obj = make_uninit_bool_vector (length); |
| 3323 | skip_dyn_eof (readcharfun); | 3401 | unsigned char *data = bool_vector_uchar_data (obj); |
| 3324 | return Qnil; | 3402 | memcpy (data, SDATA (str), size_in_chars); |
| 3325 | } | 3403 | /* Clear the extraneous bits in the last byte. */ |
| 3326 | } | 3404 | if (length != size_in_chars * BOOL_VECTOR_BITS_PER_CHAR) |
| 3405 | data[size_in_chars - 1] &= (1 << (length % BOOL_VECTOR_BITS_PER_CHAR)) - 1; | ||
| 3406 | return obj; | ||
| 3407 | } | ||
| 3408 | |||
| 3409 | /* Skip (and optionally remember) a lazily-loaded string | ||
| 3410 | preceded by "#@". */ | ||
| 3411 | static void | ||
| 3412 | skip_lazy_string (Lisp_Object readcharfun) | ||
| 3413 | { | ||
| 3414 | ptrdiff_t nskip = 0; | ||
| 3415 | ptrdiff_t digits = 0; | ||
| 3416 | for (;;) | ||
| 3417 | { | ||
| 3418 | int c = READCHAR; | ||
| 3419 | if (c < '0' || c > '9') | ||
| 3420 | { | ||
| 3327 | if (nskip > 0) | 3421 | if (nskip > 0) |
| 3328 | /* We can't use UNREAD here, because in the code below we side-step | 3422 | /* We can't use UNREAD here, because in the code below we side-step |
| 3329 | READCHAR. Instead, assume the first char after #@NNN occupies | 3423 | READCHAR. Instead, assume the first char after #@NNN occupies |
| 3330 | a single byte, which is the case normally since it's just | 3424 | a single byte, which is the case normally since it's just |
| 3331 | a space. */ | 3425 | a space. */ |
| 3332 | nskip--; | 3426 | nskip--; |
| 3333 | else | 3427 | else |
| 3334 | UNREAD (c); | 3428 | UNREAD (c); |
| 3335 | 3429 | break; | |
| 3336 | if (load_force_doc_strings | ||
| 3337 | && (FROM_FILE_P (readcharfun))) | ||
| 3338 | { | ||
| 3339 | /* If we are supposed to force doc strings into core right now, | ||
| 3340 | record the last string that we skipped, | ||
| 3341 | and record where in the file it comes from. */ | ||
| 3342 | |||
| 3343 | /* But first exchange saved_doc_string | ||
| 3344 | with prev_saved_doc_string, so we save two strings. */ | ||
| 3345 | { | ||
| 3346 | char *temp = saved_doc_string; | ||
| 3347 | ptrdiff_t temp_size = saved_doc_string_size; | ||
| 3348 | file_offset temp_pos = saved_doc_string_position; | ||
| 3349 | ptrdiff_t temp_len = saved_doc_string_length; | ||
| 3350 | |||
| 3351 | saved_doc_string = prev_saved_doc_string; | ||
| 3352 | saved_doc_string_size = prev_saved_doc_string_size; | ||
| 3353 | saved_doc_string_position = prev_saved_doc_string_position; | ||
| 3354 | saved_doc_string_length = prev_saved_doc_string_length; | ||
| 3355 | |||
| 3356 | prev_saved_doc_string = temp; | ||
| 3357 | prev_saved_doc_string_size = temp_size; | ||
| 3358 | prev_saved_doc_string_position = temp_pos; | ||
| 3359 | prev_saved_doc_string_length = temp_len; | ||
| 3360 | } | ||
| 3361 | |||
| 3362 | if (saved_doc_string_size == 0) | ||
| 3363 | { | ||
| 3364 | saved_doc_string = xmalloc (nskip + extra); | ||
| 3365 | saved_doc_string_size = nskip + extra; | ||
| 3366 | } | ||
| 3367 | if (nskip > saved_doc_string_size) | ||
| 3368 | { | ||
| 3369 | saved_doc_string = xrealloc (saved_doc_string, nskip + extra); | ||
| 3370 | saved_doc_string_size = nskip + extra; | ||
| 3371 | } | ||
| 3372 | |||
| 3373 | FILE *instream = infile->stream; | ||
| 3374 | saved_doc_string_position = (file_tell (instream) | ||
| 3375 | - infile->lookahead); | ||
| 3376 | |||
| 3377 | /* Copy that many bytes into saved_doc_string. */ | ||
| 3378 | i = 0; | ||
| 3379 | for (int n = min (nskip, infile->lookahead); 0 < n; n--) | ||
| 3380 | saved_doc_string[i++] | ||
| 3381 | = c = infile->buf[--infile->lookahead]; | ||
| 3382 | block_input (); | ||
| 3383 | for (; i < nskip && 0 <= c; i++) | ||
| 3384 | saved_doc_string[i] = c = getc (instream); | ||
| 3385 | unblock_input (); | ||
| 3386 | |||
| 3387 | saved_doc_string_length = i; | ||
| 3388 | } | ||
| 3389 | else | ||
| 3390 | /* Skip that many bytes. */ | ||
| 3391 | skip_dyn_bytes (readcharfun, nskip); | ||
| 3392 | |||
| 3393 | goto retry; | ||
| 3394 | } | 3430 | } |
| 3395 | if (c == '!') | 3431 | if (INT_MULTIPLY_WRAPV (nskip, 10, &nskip) |
| 3432 | | INT_ADD_WRAPV (nskip, c - '0', &nskip)) | ||
| 3433 | invalid_syntax ("#@", readcharfun); | ||
| 3434 | digits++; | ||
| 3435 | if (digits == 2 && nskip == 0) | ||
| 3396 | { | 3436 | { |
| 3397 | /* #! appears at the beginning of an executable file. | 3437 | /* #@00 means "skip to end" */ |
| 3398 | Skip the first line. */ | 3438 | skip_dyn_eof (readcharfun); |
| 3399 | while (c != '\n' && c >= 0) | 3439 | return; |
| 3400 | c = READCHAR; | ||
| 3401 | goto retry; | ||
| 3402 | } | 3440 | } |
| 3403 | if (c == '$') | 3441 | } |
| 3404 | return Vload_file_name; | 3442 | |
| 3405 | if (c == '\'') | 3443 | if (load_force_doc_strings && FROM_FILE_P (readcharfun)) |
| 3406 | return list2 (Qfunction, read0 (readcharfun, locate_syms)); | 3444 | { |
| 3407 | /* #:foo is the uninterned symbol named foo. */ | 3445 | /* If we are supposed to force doc strings into core right now, |
| 3408 | if (c == ':') | 3446 | record the last string that we skipped, |
| 3447 | and record where in the file it comes from. */ | ||
| 3448 | |||
| 3449 | /* But first exchange saved_doc_string | ||
| 3450 | with prev_saved_doc_string, so we save two strings. */ | ||
| 3451 | { | ||
| 3452 | char *temp = saved_doc_string; | ||
| 3453 | ptrdiff_t temp_size = saved_doc_string_size; | ||
| 3454 | file_offset temp_pos = saved_doc_string_position; | ||
| 3455 | ptrdiff_t temp_len = saved_doc_string_length; | ||
| 3456 | |||
| 3457 | saved_doc_string = prev_saved_doc_string; | ||
| 3458 | saved_doc_string_size = prev_saved_doc_string_size; | ||
| 3459 | saved_doc_string_position = prev_saved_doc_string_position; | ||
| 3460 | saved_doc_string_length = prev_saved_doc_string_length; | ||
| 3461 | |||
| 3462 | prev_saved_doc_string = temp; | ||
| 3463 | prev_saved_doc_string_size = temp_size; | ||
| 3464 | prev_saved_doc_string_position = temp_pos; | ||
| 3465 | prev_saved_doc_string_length = temp_len; | ||
| 3466 | } | ||
| 3467 | |||
| 3468 | enum { extra = 100 }; | ||
| 3469 | if (saved_doc_string_size == 0) | ||
| 3409 | { | 3470 | { |
| 3410 | uninterned_symbol = true; | 3471 | saved_doc_string = xmalloc (nskip + extra); |
| 3411 | read_hash_prefixed_symbol: | 3472 | saved_doc_string_size = nskip + extra; |
| 3412 | c = READCHAR; | ||
| 3413 | if (!(c > 040 | ||
| 3414 | && c != NO_BREAK_SPACE | ||
| 3415 | && (c >= 0200 | ||
| 3416 | || strchr ("\"';()[]#`,", c) == NULL))) | ||
| 3417 | { | ||
| 3418 | /* No symbol character follows, this is the empty | ||
| 3419 | symbol. */ | ||
| 3420 | UNREAD (c); | ||
| 3421 | return Fmake_symbol (empty_unibyte_string); | ||
| 3422 | } | ||
| 3423 | goto read_symbol; | ||
| 3424 | } | 3473 | } |
| 3425 | /* #_foo is really the symbol foo, regardless of shorthands */ | 3474 | if (nskip > saved_doc_string_size) |
| 3426 | if (c == '_') | ||
| 3427 | { | 3475 | { |
| 3428 | skip_shorthand = true; | 3476 | saved_doc_string = xrealloc (saved_doc_string, nskip + extra); |
| 3429 | goto read_hash_prefixed_symbol; | 3477 | saved_doc_string_size = nskip + extra; |
| 3430 | } | 3478 | } |
| 3431 | /* ## is the empty symbol. */ | ||
| 3432 | if (c == '#') | ||
| 3433 | return Fintern (empty_unibyte_string, Qnil); | ||
| 3434 | 3479 | ||
| 3435 | if (c >= '0' && c <= '9') | 3480 | FILE *instream = infile->stream; |
| 3436 | { | 3481 | saved_doc_string_position = (file_tell (instream) - infile->lookahead); |
| 3437 | EMACS_INT n = c - '0'; | ||
| 3438 | bool overflow = false; | ||
| 3439 | 3482 | ||
| 3440 | /* Read a non-negative integer. */ | 3483 | /* Copy that many bytes into saved_doc_string. */ |
| 3441 | while ('0' <= (c = READCHAR) && c <= '9') | 3484 | ptrdiff_t i = 0; |
| 3442 | { | 3485 | int c = 0; |
| 3443 | overflow |= INT_MULTIPLY_WRAPV (n, 10, &n); | 3486 | for (int n = min (nskip, infile->lookahead); n > 0; n--) |
| 3444 | overflow |= INT_ADD_WRAPV (n, c - '0', &n); | 3487 | saved_doc_string[i++] = c = infile->buf[--infile->lookahead]; |
| 3445 | } | 3488 | block_input (); |
| 3489 | for (; i < nskip && c >= 0; i++) | ||
| 3490 | saved_doc_string[i] = c = getc (instream); | ||
| 3491 | unblock_input (); | ||
| 3446 | 3492 | ||
| 3447 | if (!overflow) | 3493 | saved_doc_string_length = i; |
| 3448 | { | 3494 | } |
| 3449 | if (c == 'r' || c == 'R') | 3495 | else |
| 3450 | { | 3496 | /* Skip that many bytes. */ |
| 3451 | if (! (2 <= n && n <= 36)) | 3497 | skip_dyn_bytes (readcharfun, nskip); |
| 3452 | invalid_radix_integer (n, stackbuf, readcharfun); | 3498 | } |
| 3453 | return read_integer (readcharfun, n, stackbuf); | ||
| 3454 | } | ||
| 3455 | 3499 | ||
| 3456 | if (n <= MOST_POSITIVE_FIXNUM && ! NILP (Vread_circle)) | ||
| 3457 | { | ||
| 3458 | /* Reader forms that can reuse previously read objects. */ | ||
| 3459 | 3500 | ||
| 3460 | /* #n=object returns object, but associates it with | 3501 | /* Length of prefix only consisting of symbol constituent characters. */ |
| 3461 | n for #n#. */ | 3502 | static ptrdiff_t |
| 3462 | if (c == '=') | 3503 | symbol_char_span (const char *s) |
| 3463 | { | 3504 | { |
| 3464 | /* Make a placeholder for #n# to use temporarily. */ | 3505 | const char *p = s; |
| 3465 | /* Note: We used to use AUTO_CONS to allocate | 3506 | while ( *p == '^' || *p == '*' || *p == '+' || *p == '-' || *p == '/' |
| 3466 | placeholder, but that is a bad idea, since it | 3507 | || *p == '<' || *p == '=' || *p == '>' || *p == '_' || *p == '|') |
| 3467 | will place a stack-allocated cons cell into | 3508 | p++; |
| 3468 | the list in read_objects_map, which is a | 3509 | return p - s; |
| 3469 | staticpro'd global variable, and thus each of | 3510 | } |
| 3470 | its elements is marked during each GC. A | ||
| 3471 | stack-allocated object will become garbled | ||
| 3472 | when its stack slot goes out of scope, and | ||
| 3473 | some other function reuses it for entirely | ||
| 3474 | different purposes, which will cause crashes | ||
| 3475 | in GC. */ | ||
| 3476 | Lisp_Object placeholder = Fcons (Qnil, Qnil); | ||
| 3477 | struct Lisp_Hash_Table *h | ||
| 3478 | = XHASH_TABLE (read_objects_map); | ||
| 3479 | Lisp_Object number = make_fixnum (n), hash; | ||
| 3480 | |||
| 3481 | ptrdiff_t i = hash_lookup (h, number, &hash); | ||
| 3482 | if (i >= 0) | ||
| 3483 | /* Not normal, but input could be malformed. */ | ||
| 3484 | set_hash_value_slot (h, i, placeholder); | ||
| 3485 | else | ||
| 3486 | hash_put (h, number, placeholder, hash); | ||
| 3487 | |||
| 3488 | /* Read the object itself. */ | ||
| 3489 | Lisp_Object tem = read0 (readcharfun, locate_syms); | ||
| 3490 | |||
| 3491 | if (CONSP (tem)) | ||
| 3492 | { | ||
| 3493 | if (BASE_EQ (tem, placeholder)) | ||
| 3494 | /* Catch silly games like #1=#1# */ | ||
| 3495 | invalid_syntax ("nonsensical self-reference", | ||
| 3496 | readcharfun); | ||
| 3497 | 3511 | ||
| 3498 | /* Optimisation: since the placeholder is already | 3512 | static void |
| 3499 | a cons, repurpose it as the actual value. | 3513 | skip_space_and_comments (Lisp_Object readcharfun) |
| 3500 | This allows us to skip the substition below, | 3514 | { |
| 3501 | since the placeholder is already referenced | 3515 | int c; |
| 3502 | inside TEM at the appropriate places. */ | 3516 | do |
| 3503 | Fsetcar (placeholder, XCAR (tem)); | 3517 | { |
| 3504 | Fsetcdr (placeholder, XCDR (tem)); | 3518 | c = READCHAR; |
| 3505 | 3519 | if (c == ';') | |
| 3506 | struct Lisp_Hash_Table *h2 | 3520 | do |
| 3507 | = XHASH_TABLE (read_objects_completed); | 3521 | c = READCHAR; |
| 3508 | ptrdiff_t i = hash_lookup (h2, placeholder, &hash); | 3522 | while (c >= 0 && c != '\n'); |
| 3509 | eassert (i < 0); | 3523 | if (c < 0) |
| 3510 | hash_put (h2, placeholder, Qnil, hash); | 3524 | end_of_file_error (); |
| 3511 | return placeholder; | 3525 | } |
| 3512 | } | 3526 | while (c <= 32 || c == NO_BREAK_SPACE); |
| 3513 | 3527 | UNREAD (c); | |
| 3514 | /* If it can be recursive, remember it for | 3528 | } |
| 3515 | future substitutions. */ | ||
| 3516 | if (! SYMBOLP (tem) | ||
| 3517 | && ! NUMBERP (tem) | ||
| 3518 | && ! (STRINGP (tem) && !string_intervals (tem))) | ||
| 3519 | { | ||
| 3520 | struct Lisp_Hash_Table *h2 | ||
| 3521 | = XHASH_TABLE (read_objects_completed); | ||
| 3522 | i = hash_lookup (h2, tem, &hash); | ||
| 3523 | eassert (i < 0); | ||
| 3524 | hash_put (h2, tem, Qnil, hash); | ||
| 3525 | } | ||
| 3526 | |||
| 3527 | /* Now put it everywhere the placeholder was... */ | ||
| 3528 | Flread__substitute_object_in_subtree | ||
| 3529 | (tem, placeholder, read_objects_completed); | ||
| 3530 | |||
| 3531 | /* ...and #n# will use the real value from now on. */ | ||
| 3532 | i = hash_lookup (h, number, &hash); | ||
| 3533 | eassert (i >= 0); | ||
| 3534 | set_hash_value_slot (h, i, tem); | ||
| 3535 | |||
| 3536 | return tem; | ||
| 3537 | } | ||
| 3538 | 3529 | ||
| 3539 | /* #n# returns a previously read object. */ | 3530 | /* When an object is read, the type of the top read stack entry indicates |
| 3540 | if (c == '#') | 3531 | the syntactic context. */ |
| 3541 | { | 3532 | enum read_entry_type |
| 3542 | struct Lisp_Hash_Table *h | 3533 | { |
| 3543 | = XHASH_TABLE (read_objects_map); | 3534 | /* preceding syntactic context */ |
| 3544 | ptrdiff_t i = hash_lookup (h, make_fixnum (n), NULL); | 3535 | RE_list_start, /* "(" */ |
| 3545 | if (i >= 0) | 3536 | |
| 3546 | return HASH_VALUE (h, i); | 3537 | RE_list, /* "(" (+ OBJECT) */ |
| 3547 | } | 3538 | RE_list_dot, /* "(" (+ OBJECT) "." */ |
| 3548 | } | 3539 | |
| 3549 | } | 3540 | RE_vector, /* "[" (* OBJECT) */ |
| 3550 | /* Fall through to error message. */ | 3541 | RE_record, /* "#s(" (* OBJECT) */ |
| 3542 | RE_char_table, /* "#^[" (* OBJECT) */ | ||
| 3543 | RE_sub_char_table, /* "#^^[" (* OBJECT) */ | ||
| 3544 | RE_byte_code, /* "#[" (* OBJECT) */ | ||
| 3545 | RE_string_props, /* "#(" (* OBJECT) */ | ||
| 3546 | |||
| 3547 | RE_special, /* "'" | "#'" | "`" | "," | ",@" */ | ||
| 3548 | |||
| 3549 | RE_numbered, /* "#" (+ DIGIT) "=" */ | ||
| 3550 | }; | ||
| 3551 | |||
| 3552 | struct read_stack_entry | ||
| 3553 | { | ||
| 3554 | enum read_entry_type type; | ||
| 3555 | union { | ||
| 3556 | /* RE_list, RE_list_dot */ | ||
| 3557 | struct { | ||
| 3558 | Lisp_Object head; /* first cons of list */ | ||
| 3559 | Lisp_Object tail; /* last cons of list */ | ||
| 3560 | } list; | ||
| 3561 | |||
| 3562 | /* RE_vector, RE_record, RE_char_table, RE_sub_char_table, | ||
| 3563 | RE_byte_code, RE_string_props */ | ||
| 3564 | struct { | ||
| 3565 | Lisp_Object elems; /* list of elements in reverse order */ | ||
| 3566 | bool old_locate_syms; /* old value of locate_syms */ | ||
| 3567 | } vector; | ||
| 3568 | |||
| 3569 | /* RE_special */ | ||
| 3570 | struct { | ||
| 3571 | Lisp_Object symbol; /* symbol from special syntax */ | ||
| 3572 | } special; | ||
| 3573 | |||
| 3574 | /* RE_numbered */ | ||
| 3575 | struct { | ||
| 3576 | Lisp_Object number; /* number as a fixnum */ | ||
| 3577 | Lisp_Object placeholder; /* placeholder object */ | ||
| 3578 | } numbered; | ||
| 3579 | } u; | ||
| 3580 | }; | ||
| 3581 | |||
| 3582 | struct read_stack | ||
| 3583 | { | ||
| 3584 | struct read_stack_entry *stack; /* base of stack */ | ||
| 3585 | ptrdiff_t size; /* allocated size in entries */ | ||
| 3586 | ptrdiff_t sp; /* current number of entries */ | ||
| 3587 | }; | ||
| 3588 | |||
| 3589 | static struct read_stack rdstack = {NULL, 0, 0}; | ||
| 3590 | |||
| 3591 | void | ||
| 3592 | mark_lread (void) | ||
| 3593 | { | ||
| 3594 | /* Mark the read stack, which may contain data not otherwise traced */ | ||
| 3595 | for (ptrdiff_t i = 0; i < rdstack.sp; i++) | ||
| 3596 | { | ||
| 3597 | struct read_stack_entry *e = &rdstack.stack[i]; | ||
| 3598 | switch (e->type) | ||
| 3599 | { | ||
| 3600 | case RE_list_start: | ||
| 3601 | break; | ||
| 3602 | case RE_list: | ||
| 3603 | case RE_list_dot: | ||
| 3604 | mark_object (e->u.list.head); | ||
| 3605 | mark_object (e->u.list.tail); | ||
| 3606 | break; | ||
| 3607 | case RE_vector: | ||
| 3608 | case RE_record: | ||
| 3609 | case RE_char_table: | ||
| 3610 | case RE_sub_char_table: | ||
| 3611 | case RE_byte_code: | ||
| 3612 | case RE_string_props: | ||
| 3613 | mark_object (e->u.vector.elems); | ||
| 3614 | break; | ||
| 3615 | case RE_special: | ||
| 3616 | mark_object (e->u.special.symbol); | ||
| 3617 | break; | ||
| 3618 | case RE_numbered: | ||
| 3619 | mark_object (e->u.numbered.number); | ||
| 3620 | mark_object (e->u.numbered.placeholder); | ||
| 3621 | break; | ||
| 3551 | } | 3622 | } |
| 3552 | else if (c == 'x' || c == 'X') | 3623 | } |
| 3553 | return read_integer (readcharfun, 16, stackbuf); | 3624 | } |
| 3554 | else if (c == 'o' || c == 'O') | ||
| 3555 | return read_integer (readcharfun, 8, stackbuf); | ||
| 3556 | else if (c == 'b' || c == 'B') | ||
| 3557 | return read_integer (readcharfun, 2, stackbuf); | ||
| 3558 | |||
| 3559 | char acm_buf[15]; /* FIXME!!! 2021-11-27. */ | ||
| 3560 | sprintf (acm_buf, "#%c", c); | ||
| 3561 | invalid_syntax (acm_buf, readcharfun); | ||
| 3562 | UNREAD (c); | ||
| 3563 | invalid_syntax ("#", readcharfun); | ||
| 3564 | 3625 | ||
| 3565 | case ';': | 3626 | static inline struct read_stack_entry * |
| 3566 | while ((c = READCHAR) >= 0 && c != '\n'); | 3627 | read_stack_top (void) |
| 3567 | goto retry; | 3628 | { |
| 3629 | eassume (rdstack.sp > 0); | ||
| 3630 | return &rdstack.stack[rdstack.sp - 1]; | ||
| 3631 | } | ||
| 3568 | 3632 | ||
| 3569 | case '\'': | 3633 | static inline struct read_stack_entry * |
| 3570 | return list2 (Qquote, read0 (readcharfun, locate_syms)); | 3634 | read_stack_pop (void) |
| 3635 | { | ||
| 3636 | eassume (rdstack.sp > 0); | ||
| 3637 | return &rdstack.stack[--rdstack.sp]; | ||
| 3638 | } | ||
| 3571 | 3639 | ||
| 3572 | case '`': | 3640 | static inline bool |
| 3573 | return list2 (Qbackquote, read0 (readcharfun, locate_syms)); | 3641 | read_stack_empty_p (ptrdiff_t base_sp) |
| 3642 | { | ||
| 3643 | return rdstack.sp <= base_sp; | ||
| 3644 | } | ||
| 3574 | 3645 | ||
| 3575 | case ',': | 3646 | NO_INLINE static void |
| 3576 | { | 3647 | grow_read_stack (void) |
| 3577 | Lisp_Object comma_type = Qnil; | 3648 | { |
| 3578 | Lisp_Object value; | 3649 | struct read_stack *rs = &rdstack; |
| 3579 | int ch = READCHAR; | 3650 | eassert (rs->sp == rs->size); |
| 3651 | rs->stack = xpalloc (rs->stack, &rs->size, 1, -1, sizeof *rs->stack); | ||
| 3652 | eassert (rs->sp < rs->size); | ||
| 3653 | } | ||
| 3580 | 3654 | ||
| 3581 | if (ch == '@') | 3655 | static inline void |
| 3582 | comma_type = Qcomma_at; | 3656 | read_stack_push (struct read_stack_entry e) |
| 3583 | else | 3657 | { |
| 3584 | { | 3658 | if (rdstack.sp >= rdstack.size) |
| 3585 | if (ch >= 0) UNREAD (ch); | 3659 | grow_read_stack (); |
| 3586 | comma_type = Qcomma; | 3660 | rdstack.stack[rdstack.sp++] = e; |
| 3587 | } | 3661 | } |
| 3588 | 3662 | ||
| 3589 | value = read0 (readcharfun, locate_syms); | ||
| 3590 | return list2 (comma_type, value); | ||
| 3591 | } | ||
| 3592 | case '?': | ||
| 3593 | { | ||
| 3594 | int modifiers; | ||
| 3595 | int next_char; | ||
| 3596 | bool ok; | ||
| 3597 | 3663 | ||
| 3598 | c = READCHAR; | 3664 | /* Read a Lisp object. |
| 3599 | if (c < 0) | 3665 | If LOCATE_SYMS is true, symbols are read with position. */ |
| 3600 | end_of_file_error (); | 3666 | static Lisp_Object |
| 3601 | 3667 | read0 (Lisp_Object readcharfun, bool locate_syms) | |
| 3602 | /* Accept `single space' syntax like (list ? x) where the | 3668 | { |
| 3603 | whitespace character is SPC or TAB. | 3669 | char stackbuf[stackbufsize]; |
| 3604 | Other literal whitespace like NL, CR, and FF are not accepted, | 3670 | char *read_buffer = stackbuf; |
| 3605 | as there are well-established escape sequences for these. */ | 3671 | ptrdiff_t read_buffer_size = sizeof stackbuf; |
| 3606 | if (c == ' ' || c == '\t') | 3672 | char *heapbuf = NULL; |
| 3607 | return make_fixnum (c); | 3673 | specpdl_ref count = SPECPDL_INDEX (); |
| 3608 | 3674 | ||
| 3609 | if (c == '(' || c == ')' || c == '[' || c == ']' | 3675 | ptrdiff_t base_sp = rdstack.sp; |
| 3610 | || c == '"' || c == ';') | 3676 | |
| 3677 | bool uninterned_symbol; | ||
| 3678 | bool skip_shorthand; | ||
| 3679 | |||
| 3680 | /* Read an object into `obj'. */ | ||
| 3681 | read_obj: ; | ||
| 3682 | Lisp_Object obj; | ||
| 3683 | bool multibyte; | ||
| 3684 | int c = READCHAR_REPORT_MULTIBYTE (&multibyte); | ||
| 3685 | if (c < 0) | ||
| 3686 | end_of_file_error (); | ||
| 3687 | |||
| 3688 | switch (c) | ||
| 3689 | { | ||
| 3690 | case '(': | ||
| 3691 | read_stack_push ((struct read_stack_entry) {.type = RE_list_start}); | ||
| 3692 | goto read_obj; | ||
| 3693 | |||
| 3694 | case ')': | ||
| 3695 | if (read_stack_empty_p (base_sp)) | ||
| 3696 | invalid_syntax (")", readcharfun); | ||
| 3697 | switch (read_stack_top ()->type) | ||
| 3698 | { | ||
| 3699 | case RE_list_start: | ||
| 3700 | read_stack_pop (); | ||
| 3701 | obj = Qnil; | ||
| 3702 | break; | ||
| 3703 | case RE_list: | ||
| 3704 | obj = read_stack_pop ()->u.list.head; | ||
| 3705 | break; | ||
| 3706 | case RE_record: | ||
| 3611 | { | 3707 | { |
| 3612 | CHECK_LIST (Vlread_unescaped_character_literals); | 3708 | locate_syms = read_stack_top ()->u.vector.old_locate_syms; |
| 3613 | Lisp_Object char_obj = make_fixed_natnum (c); | 3709 | Lisp_Object elems = Fnreverse (read_stack_pop ()->u.vector.elems); |
| 3614 | if (NILP (Fmemq (char_obj, Vlread_unescaped_character_literals))) | 3710 | if (NILP (elems)) |
| 3615 | Vlread_unescaped_character_literals = | 3711 | invalid_syntax ("#s", readcharfun); |
| 3616 | Fcons (char_obj, Vlread_unescaped_character_literals); | 3712 | |
| 3713 | if (BASE_EQ (XCAR (elems), Qhash_table)) | ||
| 3714 | obj = hash_table_from_plist (XCDR (elems)); | ||
| 3715 | else | ||
| 3716 | obj = record_from_list (elems); | ||
| 3717 | break; | ||
| 3617 | } | 3718 | } |
| 3719 | case RE_string_props: | ||
| 3720 | locate_syms = read_stack_top ()->u.vector.old_locate_syms; | ||
| 3721 | obj = string_props_from_rev_list (read_stack_pop () ->u.vector.elems, | ||
| 3722 | readcharfun); | ||
| 3723 | break; | ||
| 3724 | default: | ||
| 3725 | invalid_syntax (")", readcharfun); | ||
| 3726 | } | ||
| 3727 | break; | ||
| 3618 | 3728 | ||
| 3619 | if (c == '\\') | 3729 | case '[': |
| 3620 | c = read_escape (readcharfun, 0); | 3730 | read_stack_push ((struct read_stack_entry) { |
| 3621 | modifiers = c & CHAR_MODIFIER_MASK; | 3731 | .type = RE_vector, |
| 3622 | c &= ~CHAR_MODIFIER_MASK; | 3732 | .u.vector.elems = Qnil, |
| 3623 | if (CHAR_BYTE8_P (c)) | 3733 | .u.vector.old_locate_syms = locate_syms, |
| 3624 | c = CHAR_TO_BYTE8 (c); | 3734 | }); |
| 3625 | c |= modifiers; | 3735 | /* FIXME: should vectors be read with locate_syms=false? */ |
| 3626 | 3736 | goto read_obj; | |
| 3627 | next_char = READCHAR; | ||
| 3628 | ok = (next_char <= 040 | ||
| 3629 | || (next_char < 0200 | ||
| 3630 | && strchr ("\"';()[]#?`,.", next_char) != NULL)); | ||
| 3631 | UNREAD (next_char); | ||
| 3632 | if (ok) | ||
| 3633 | return make_fixnum (c); | ||
| 3634 | |||
| 3635 | invalid_syntax ("?", readcharfun); | ||
| 3636 | } | ||
| 3637 | 3737 | ||
| 3638 | case '"': | 3738 | case ']': |
| 3739 | if (read_stack_empty_p (base_sp)) | ||
| 3740 | invalid_syntax ("]", readcharfun); | ||
| 3741 | switch (read_stack_top ()->type) | ||
| 3742 | { | ||
| 3743 | case RE_vector: | ||
| 3744 | locate_syms = read_stack_top ()->u.vector.old_locate_syms; | ||
| 3745 | obj = vector_from_rev_list (read_stack_pop ()->u.vector.elems); | ||
| 3746 | break; | ||
| 3747 | case RE_byte_code: | ||
| 3748 | locate_syms = read_stack_top ()->u.vector.old_locate_syms; | ||
| 3749 | obj = bytecode_from_rev_list (read_stack_pop ()->u.vector.elems, | ||
| 3750 | readcharfun); | ||
| 3751 | break; | ||
| 3752 | case RE_char_table: | ||
| 3753 | locate_syms = read_stack_top ()->u.vector.old_locate_syms; | ||
| 3754 | obj = char_table_from_rev_list (read_stack_pop ()->u.vector.elems, | ||
| 3755 | readcharfun); | ||
| 3756 | break; | ||
| 3757 | case RE_sub_char_table: | ||
| 3758 | locate_syms = read_stack_top ()->u.vector.old_locate_syms; | ||
| 3759 | obj = sub_char_table_from_rev_list (read_stack_pop ()->u.vector.elems, | ||
| 3760 | readcharfun); | ||
| 3761 | break; | ||
| 3762 | default: | ||
| 3763 | invalid_syntax ("]", readcharfun); | ||
| 3764 | break; | ||
| 3765 | } | ||
| 3766 | break; | ||
| 3767 | |||
| 3768 | case '#': | ||
| 3639 | { | 3769 | { |
| 3640 | specpdl_ref count = SPECPDL_INDEX (); | 3770 | int ch = READCHAR; |
| 3641 | char *read_buffer = stackbuf; | 3771 | switch (ch) |
| 3642 | ptrdiff_t read_buffer_size = sizeof stackbuf; | ||
| 3643 | char *heapbuf = NULL; | ||
| 3644 | char *p = read_buffer; | ||
| 3645 | char *end = read_buffer + read_buffer_size; | ||
| 3646 | int ch; | ||
| 3647 | /* True if we saw an escape sequence specifying | ||
| 3648 | a multibyte character. */ | ||
| 3649 | bool force_multibyte = false; | ||
| 3650 | /* True if we saw an escape sequence specifying | ||
| 3651 | a single-byte character. */ | ||
| 3652 | bool force_singlebyte = false; | ||
| 3653 | bool cancel = false; | ||
| 3654 | ptrdiff_t nchars = 0; | ||
| 3655 | |||
| 3656 | while ((ch = READCHAR) >= 0 | ||
| 3657 | && ch != '\"') | ||
| 3658 | { | 3772 | { |
| 3659 | if (end - p < MAX_MULTIBYTE_LENGTH) | 3773 | case '\'': |
| 3774 | /* #'X -- special syntax for (function X) */ | ||
| 3775 | read_stack_push ((struct read_stack_entry) { | ||
| 3776 | .type = RE_special, | ||
| 3777 | .u.special.symbol = Qfunction, | ||
| 3778 | }); | ||
| 3779 | goto read_obj; | ||
| 3780 | |||
| 3781 | case '#': | ||
| 3782 | /* ## -- the empty symbol */ | ||
| 3783 | obj = Fintern (empty_unibyte_string, Qnil); | ||
| 3784 | break; | ||
| 3785 | |||
| 3786 | case 's': | ||
| 3787 | /* #s(...) -- a record or hash-table */ | ||
| 3788 | ch = READCHAR; | ||
| 3789 | if (ch != '(') | ||
| 3660 | { | 3790 | { |
| 3661 | ptrdiff_t offset = p - read_buffer; | 3791 | UNREAD (ch); |
| 3662 | read_buffer = grow_read_buffer (read_buffer, offset, | 3792 | invalid_syntax ("#s", readcharfun); |
| 3663 | &heapbuf, &read_buffer_size, | ||
| 3664 | count); | ||
| 3665 | p = read_buffer + offset; | ||
| 3666 | end = read_buffer + read_buffer_size; | ||
| 3667 | } | 3793 | } |
| 3794 | read_stack_push ((struct read_stack_entry) { | ||
| 3795 | .type = RE_record, | ||
| 3796 | .u.vector.elems = Qnil, | ||
| 3797 | .u.vector.old_locate_syms = locate_syms, | ||
| 3798 | }); | ||
| 3799 | locate_syms = false; | ||
| 3800 | goto read_obj; | ||
| 3801 | |||
| 3802 | case '^': | ||
| 3803 | /* #^[...] -- char-table | ||
| 3804 | #^^[...] -- sub-char-table */ | ||
| 3805 | ch = READCHAR; | ||
| 3806 | if (ch == '^') | ||
| 3807 | { | ||
| 3808 | ch = READCHAR; | ||
| 3809 | if (ch == '[') | ||
| 3810 | { | ||
| 3811 | read_stack_push ((struct read_stack_entry) { | ||
| 3812 | .type = RE_sub_char_table, | ||
| 3813 | .u.vector.elems = Qnil, | ||
| 3814 | .u.vector.old_locate_syms = locate_syms, | ||
| 3815 | }); | ||
| 3816 | locate_syms = false; | ||
| 3817 | goto read_obj; | ||
| 3818 | } | ||
| 3819 | else | ||
| 3820 | { | ||
| 3821 | UNREAD (ch); | ||
| 3822 | invalid_syntax ("#^^", readcharfun); | ||
| 3823 | } | ||
| 3824 | } | ||
| 3825 | else if (ch == '[') | ||
| 3826 | { | ||
| 3827 | read_stack_push ((struct read_stack_entry) { | ||
| 3828 | .type = RE_char_table, | ||
| 3829 | .u.vector.elems = Qnil, | ||
| 3830 | .u.vector.old_locate_syms = locate_syms, | ||
| 3831 | }); | ||
| 3832 | locate_syms = false; | ||
| 3833 | goto read_obj; | ||
| 3834 | } | ||
| 3835 | else | ||
| 3836 | { | ||
| 3837 | UNREAD (ch); | ||
| 3838 | invalid_syntax ("#^", readcharfun); | ||
| 3839 | } | ||
| 3840 | |||
| 3841 | case '(': | ||
| 3842 | /* #(...) -- string with properties */ | ||
| 3843 | read_stack_push ((struct read_stack_entry) { | ||
| 3844 | .type = RE_string_props, | ||
| 3845 | .u.vector.elems = Qnil, | ||
| 3846 | .u.vector.old_locate_syms = locate_syms, | ||
| 3847 | }); | ||
| 3848 | locate_syms = false; | ||
| 3849 | goto read_obj; | ||
| 3850 | |||
| 3851 | case '[': | ||
| 3852 | /* #[...] -- byte-code */ | ||
| 3853 | read_stack_push ((struct read_stack_entry) { | ||
| 3854 | .type = RE_byte_code, | ||
| 3855 | .u.vector.elems = Qnil, | ||
| 3856 | .u.vector.old_locate_syms = locate_syms, | ||
| 3857 | }); | ||
| 3858 | locate_syms = false; | ||
| 3859 | goto read_obj; | ||
| 3860 | |||
| 3861 | case '&': | ||
| 3862 | /* #&N"..." -- bool-vector */ | ||
| 3863 | obj = read_bool_vector (stackbuf, readcharfun); | ||
| 3864 | break; | ||
| 3865 | |||
| 3866 | case '!': | ||
| 3867 | /* #! appears at the beginning of an executable file. | ||
| 3868 | Skip the rest of the line. */ | ||
| 3869 | { | ||
| 3870 | int c; | ||
| 3871 | do | ||
| 3872 | c = READCHAR; | ||
| 3873 | while (c >= 0 && c != '\n'); | ||
| 3874 | goto read_obj; | ||
| 3875 | } | ||
| 3668 | 3876 | ||
| 3669 | if (ch == '\\') | 3877 | case 'x': |
| 3878 | case 'X': | ||
| 3879 | obj = read_integer (readcharfun, 16, stackbuf); | ||
| 3880 | break; | ||
| 3881 | |||
| 3882 | case 'o': | ||
| 3883 | case 'O': | ||
| 3884 | obj = read_integer (readcharfun, 8, stackbuf); | ||
| 3885 | break; | ||
| 3886 | |||
| 3887 | case 'b': | ||
| 3888 | case 'B': | ||
| 3889 | obj = read_integer (readcharfun, 2, stackbuf); | ||
| 3890 | break; | ||
| 3891 | |||
| 3892 | case '@': | ||
| 3893 | /* #@NUMBER is used to skip NUMBER following bytes. | ||
| 3894 | That's used in .elc files to skip over doc strings | ||
| 3895 | and function definitions that can be loaded lazily. */ | ||
| 3896 | skip_lazy_string (readcharfun); | ||
| 3897 | goto read_obj; | ||
| 3898 | |||
| 3899 | case '$': | ||
| 3900 | /* #$ -- reference to lazy-loaded string */ | ||
| 3901 | obj = Vload_file_name; | ||
| 3902 | break; | ||
| 3903 | |||
| 3904 | case ':': | ||
| 3905 | /* #:X -- uninterned symbol */ | ||
| 3906 | c = READCHAR; | ||
| 3907 | if (c <= 32 || c == NO_BREAK_SPACE | ||
| 3908 | || c == '"' || c == '\'' || c == ';' || c == '#' | ||
| 3909 | || c == '(' || c == ')' || c == '[' || c == ']' | ||
| 3910 | || c == '`' || c == ',') | ||
| 3670 | { | 3911 | { |
| 3671 | int modifiers; | 3912 | /* No symbol character follows: this is the empty symbol. */ |
| 3913 | UNREAD (c); | ||
| 3914 | obj = Fmake_symbol (empty_unibyte_string); | ||
| 3915 | break; | ||
| 3916 | } | ||
| 3917 | uninterned_symbol = true; | ||
| 3918 | skip_shorthand = false; | ||
| 3919 | goto read_symbol; | ||
| 3672 | 3920 | ||
| 3673 | ch = read_escape (readcharfun, 1); | 3921 | case '_': |
| 3922 | /* #_X -- symbol without shorthand */ | ||
| 3923 | c = READCHAR; | ||
| 3924 | if (c <= 32 || c == NO_BREAK_SPACE | ||
| 3925 | || c == '"' || c == '\'' || c == ';' || c == '#' | ||
| 3926 | || c == '(' || c == ')' || c == '[' || c == ']' | ||
| 3927 | || c == '`' || c == ',') | ||
| 3928 | { | ||
| 3929 | /* No symbol character follows: this is the empty symbol. */ | ||
| 3930 | UNREAD (c); | ||
| 3931 | obj = Fintern (empty_unibyte_string, Qnil); | ||
| 3932 | break; | ||
| 3933 | } | ||
| 3934 | uninterned_symbol = false; | ||
| 3935 | skip_shorthand = true; | ||
| 3936 | goto read_symbol; | ||
| 3674 | 3937 | ||
| 3675 | /* CH is -1 if \ newline or \ space has just been seen. */ | 3938 | default: |
| 3676 | if (ch == -1) | 3939 | if (ch >= '0' && ch <= '9') |
| 3940 | { | ||
| 3941 | /* #N=OBJ or #N# -- first read the number N */ | ||
| 3942 | EMACS_INT n = ch - '0'; | ||
| 3943 | int c; | ||
| 3944 | for (;;) | ||
| 3677 | { | 3945 | { |
| 3678 | if (p == read_buffer) | 3946 | c = READCHAR; |
| 3679 | cancel = true; | 3947 | if (c < '0' || c > '9') |
| 3680 | continue; | 3948 | break; |
| 3949 | if (INT_MULTIPLY_WRAPV (n, 10, &n) | ||
| 3950 | || INT_ADD_WRAPV (n, c - '0', &n)) | ||
| 3951 | invalid_syntax ("#", readcharfun); | ||
| 3681 | } | 3952 | } |
| 3682 | 3953 | if (c == 'r' || c == 'R') | |
| 3683 | modifiers = ch & CHAR_MODIFIER_MASK; | ||
| 3684 | ch = ch & ~CHAR_MODIFIER_MASK; | ||
| 3685 | |||
| 3686 | if (CHAR_BYTE8_P (ch)) | ||
| 3687 | force_singlebyte = true; | ||
| 3688 | else if (! ASCII_CHAR_P (ch)) | ||
| 3689 | force_multibyte = true; | ||
| 3690 | else /* I.e. ASCII_CHAR_P (ch). */ | ||
| 3691 | { | 3954 | { |
| 3692 | /* Allow `\C- ' and `\C-?'. */ | 3955 | /* #NrDIGITS -- radix-N number */ |
| 3693 | if (modifiers == CHAR_CTL) | 3956 | if (n < 0 || n > 36) |
| 3694 | { | 3957 | invalid_radix_integer (n, stackbuf, readcharfun); |
| 3695 | if (ch == ' ') | 3958 | obj = read_integer (readcharfun, n, stackbuf); |
| 3696 | ch = 0, modifiers = 0; | 3959 | break; |
| 3697 | else if (ch == '?') | 3960 | } |
| 3698 | ch = 127, modifiers = 0; | 3961 | else if (n <= MOST_POSITIVE_FIXNUM && !NILP (Vread_circle)) |
| 3699 | } | 3962 | { |
| 3700 | if (modifiers & CHAR_SHIFT) | 3963 | if (c == '=') |
| 3701 | { | 3964 | { |
| 3702 | /* Shift modifier is valid only with [A-Za-z]. */ | 3965 | /* #N=OBJ -- assign number N to OBJ */ |
| 3703 | if (ch >= 'A' && ch <= 'Z') | 3966 | Lisp_Object placeholder = Fcons (Qnil, Qnil); |
| 3704 | modifiers &= ~CHAR_SHIFT; | 3967 | |
| 3705 | else if (ch >= 'a' && ch <= 'z') | 3968 | struct Lisp_Hash_Table *h |
| 3706 | ch -= ('a' - 'A'), modifiers &= ~CHAR_SHIFT; | 3969 | = XHASH_TABLE (read_objects_map); |
| 3970 | Lisp_Object number = make_fixnum (n); | ||
| 3971 | Lisp_Object hash; | ||
| 3972 | ptrdiff_t i = hash_lookup (h, number, &hash); | ||
| 3973 | if (i >= 0) | ||
| 3974 | /* Not normal, but input could be malformed. */ | ||
| 3975 | set_hash_value_slot (h, i, placeholder); | ||
| 3976 | else | ||
| 3977 | hash_put (h, number, placeholder, hash); | ||
| 3978 | read_stack_push ((struct read_stack_entry) { | ||
| 3979 | .type = RE_numbered, | ||
| 3980 | .u.numbered.number = number, | ||
| 3981 | .u.numbered.placeholder = placeholder, | ||
| 3982 | }); | ||
| 3983 | goto read_obj; | ||
| 3707 | } | 3984 | } |
| 3708 | 3985 | else if (c == '#') | |
| 3709 | if (modifiers & CHAR_META) | ||
| 3710 | { | 3986 | { |
| 3711 | /* Move the meta bit to the right place for a | 3987 | /* #N# -- reference to numbered object */ |
| 3712 | string. */ | 3988 | struct Lisp_Hash_Table *h |
| 3713 | modifiers &= ~CHAR_META; | 3989 | = XHASH_TABLE (read_objects_map); |
| 3714 | ch = BYTE8_TO_CHAR (ch | 0x80); | 3990 | ptrdiff_t i = hash_lookup (h, make_fixnum (n), NULL); |
| 3715 | force_singlebyte = true; | 3991 | if (i < 0) |
| 3992 | invalid_syntax ("#", readcharfun); | ||
| 3993 | obj = HASH_VALUE (h, i); | ||
| 3994 | break; | ||
| 3716 | } | 3995 | } |
| 3996 | else | ||
| 3997 | invalid_syntax ("#", readcharfun); | ||
| 3717 | } | 3998 | } |
| 3718 | 3999 | else | |
| 3719 | /* Any modifiers remaining are invalid. */ | 4000 | invalid_syntax ("#", readcharfun); |
| 3720 | if (modifiers) | ||
| 3721 | invalid_syntax ("Invalid modifier in string", readcharfun); | ||
| 3722 | p += CHAR_STRING (ch, (unsigned char *) p); | ||
| 3723 | } | 4001 | } |
| 3724 | else | 4002 | else |
| 3725 | { | 4003 | invalid_syntax ("#", readcharfun); |
| 3726 | p += CHAR_STRING (ch, (unsigned char *) p); | ||
| 3727 | if (CHAR_BYTE8_P (ch)) | ||
| 3728 | force_singlebyte = true; | ||
| 3729 | else if (! ASCII_CHAR_P (ch)) | ||
| 3730 | force_multibyte = true; | ||
| 3731 | } | ||
| 3732 | nchars++; | ||
| 3733 | } | 4004 | } |
| 4005 | break; | ||
| 4006 | } | ||
| 3734 | 4007 | ||
| 3735 | if (ch < 0) | 4008 | case '?': |
| 3736 | end_of_file_error (); | 4009 | obj = read_char_literal (readcharfun); |
| 4010 | break; | ||
| 3737 | 4011 | ||
| 3738 | /* If purifying, and string starts with \ newline, | 4012 | case '"': |
| 3739 | return zero instead. This is for doc strings | 4013 | obj = read_string_literal (stackbuf, readcharfun); |
| 3740 | that we are really going to find in etc/DOC.nn.nn. */ | 4014 | break; |
| 3741 | if (!NILP (Vpurify_flag) && NILP (Vdoc_file_name) && cancel) | 4015 | |
| 3742 | return unbind_to (count, make_fixnum (0)); | 4016 | case '\'': |
| 4017 | read_stack_push ((struct read_stack_entry) { | ||
| 4018 | .type = RE_special, | ||
| 4019 | .u.special.symbol = Qquote, | ||
| 4020 | }); | ||
| 4021 | goto read_obj; | ||
| 3743 | 4022 | ||
| 3744 | if (! force_multibyte && force_singlebyte) | 4023 | case '`': |
| 4024 | read_stack_push ((struct read_stack_entry) { | ||
| 4025 | .type = RE_special, | ||
| 4026 | .u.special.symbol = Qbackquote, | ||
| 4027 | }); | ||
| 4028 | goto read_obj; | ||
| 4029 | |||
| 4030 | case ',': | ||
| 4031 | { | ||
| 4032 | int ch = READCHAR; | ||
| 4033 | Lisp_Object sym; | ||
| 4034 | if (ch == '@') | ||
| 4035 | sym = Qcomma_at; | ||
| 4036 | else | ||
| 3745 | { | 4037 | { |
| 3746 | /* READ_BUFFER contains raw 8-bit bytes and no multibyte | 4038 | if (ch >= 0) |
| 3747 | forms. Convert it to unibyte. */ | 4039 | UNREAD (ch); |
| 3748 | nchars = str_as_unibyte ((unsigned char *) read_buffer, | 4040 | sym = Qcomma; |
| 3749 | p - read_buffer); | ||
| 3750 | p = read_buffer + nchars; | ||
| 3751 | } | 4041 | } |
| 4042 | read_stack_push ((struct read_stack_entry) { | ||
| 4043 | .type = RE_special, | ||
| 4044 | .u.special.symbol = sym, | ||
| 4045 | }); | ||
| 4046 | goto read_obj; | ||
| 4047 | } | ||
| 3752 | 4048 | ||
| 3753 | Lisp_Object result | 4049 | case ';': |
| 3754 | = make_specified_string (read_buffer, nchars, p - read_buffer, | 4050 | { |
| 3755 | (force_multibyte | 4051 | int c; |
| 3756 | || (p - read_buffer != nchars))); | 4052 | do |
| 3757 | return unbind_to (count, result); | 4053 | c = READCHAR; |
| 4054 | while (c >= 0 && c != '\n'); | ||
| 4055 | goto read_obj; | ||
| 3758 | } | 4056 | } |
| 3759 | 4057 | ||
| 3760 | case '.': | 4058 | case '.': |
| 3761 | { | 4059 | { |
| 3762 | int next_char = READCHAR; | 4060 | int nch = READCHAR; |
| 3763 | UNREAD (next_char); | 4061 | UNREAD (nch); |
| 3764 | 4062 | if (nch <= 32 || nch == NO_BREAK_SPACE | |
| 3765 | if (next_char <= 040 | 4063 | || nch == '"' || nch == '\'' || nch == ';' |
| 3766 | || (next_char < 0200 | 4064 | || nch == '(' || nch == '[' || nch == '#' |
| 3767 | && strchr ("\"';([#?`,", next_char) != NULL)) | 4065 | || nch == '?' || nch == '`' || nch == ',') |
| 3768 | { | 4066 | { |
| 3769 | *pch = c; | 4067 | if (!read_stack_empty_p (base_sp) |
| 3770 | return Qnil; | 4068 | && read_stack_top ()->type == RE_list) |
| 4069 | { | ||
| 4070 | read_stack_top ()->type = RE_list_dot; | ||
| 4071 | goto read_obj; | ||
| 4072 | } | ||
| 4073 | invalid_syntax (".", readcharfun); | ||
| 3771 | } | 4074 | } |
| 3772 | } | 4075 | } |
| 3773 | /* The atom-reading loop below will now loop at least once, | 4076 | /* may be a number or symbol starting with a dot */ |
| 3774 | assuring that we will not try to UNREAD two characters in a | ||
| 3775 | row. */ | ||
| 3776 | FALLTHROUGH; | 4077 | FALLTHROUGH; |
| 4078 | |||
| 3777 | default: | 4079 | default: |
| 3778 | if (c <= 040) goto retry; | 4080 | if (c <= 32 || c == NO_BREAK_SPACE) |
| 3779 | if (c == NO_BREAK_SPACE) | 4081 | goto read_obj; |
| 3780 | goto retry; | ||
| 3781 | 4082 | ||
| 4083 | uninterned_symbol = false; | ||
| 4084 | skip_shorthand = false; | ||
| 4085 | /* symbol or number */ | ||
| 3782 | read_symbol: | 4086 | read_symbol: |
| 3783 | { | 4087 | { |
| 3784 | specpdl_ref count = SPECPDL_INDEX (); | ||
| 3785 | char *read_buffer = stackbuf; | ||
| 3786 | ptrdiff_t read_buffer_size = sizeof stackbuf; | ||
| 3787 | char *heapbuf = NULL; | ||
| 3788 | char *p = read_buffer; | 4088 | char *p = read_buffer; |
| 3789 | char *end = read_buffer + read_buffer_size; | 4089 | char *end = read_buffer + read_buffer_size; |
| 3790 | bool quoted = false; | 4090 | bool quoted = false; |
| @@ -3805,7 +4105,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list, bool locate_syms) | |||
| 3805 | if (c == '\\') | 4105 | if (c == '\\') |
| 3806 | { | 4106 | { |
| 3807 | c = READCHAR; | 4107 | c = READCHAR; |
| 3808 | if (c == -1) | 4108 | if (c < 0) |
| 3809 | end_of_file_error (); | 4109 | end_of_file_error (); |
| 3810 | quoted = true; | 4110 | quoted = true; |
| 3811 | } | 4111 | } |
| @@ -3816,94 +4116,205 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list, bool locate_syms) | |||
| 3816 | *p++ = c; | 4116 | *p++ = c; |
| 3817 | c = READCHAR; | 4117 | c = READCHAR; |
| 3818 | } | 4118 | } |
| 3819 | while (c > 040 | 4119 | while (c > 32 |
| 3820 | && c != NO_BREAK_SPACE | 4120 | && c != NO_BREAK_SPACE |
| 3821 | && (c >= 0200 | 4121 | && (c >= 128 |
| 3822 | || strchr ("\"';()[]#`,", c) == NULL)); | 4122 | || !( c == '"' || c == '\'' || c == ';' || c == '#' |
| 4123 | || c == '(' || c == ')' || c == '[' || c == ']' | ||
| 4124 | || c == '`' || c == ','))); | ||
| 3823 | 4125 | ||
| 3824 | *p = 0; | 4126 | *p = 0; |
| 3825 | ptrdiff_t nbytes = p - read_buffer; | 4127 | ptrdiff_t nbytes = p - read_buffer; |
| 3826 | UNREAD (c); | 4128 | UNREAD (c); |
| 3827 | 4129 | ||
| 3828 | if (!quoted && !uninterned_symbol && !skip_shorthand) | 4130 | /* Only attempt to parse the token as a number if it starts as one. */ |
| 4131 | char c0 = read_buffer[0]; | ||
| 4132 | if (((c0 >= '0' && c0 <= '9') || c0 == '.' || c0 == '-' || c0 == '+') | ||
| 4133 | && !quoted && !uninterned_symbol && !skip_shorthand) | ||
| 3829 | { | 4134 | { |
| 3830 | ptrdiff_t len; | 4135 | ptrdiff_t len; |
| 3831 | Lisp_Object result = string_to_number (read_buffer, 10, &len); | 4136 | Lisp_Object result = string_to_number (read_buffer, 10, &len); |
| 3832 | if (! NILP (result) && len == nbytes) | 4137 | if (!NILP (result) && len == nbytes) |
| 3833 | return unbind_to (count, result); | 4138 | { |
| 4139 | obj = result; | ||
| 4140 | break; | ||
| 4141 | } | ||
| 3834 | } | 4142 | } |
| 3835 | { | 4143 | |
| 3836 | Lisp_Object result; | 4144 | /* symbol, possibly uninterned */ |
| 3837 | ptrdiff_t nchars | 4145 | ptrdiff_t nchars |
| 3838 | = (multibyte | 4146 | = (multibyte |
| 3839 | ? multibyte_chars_in_text ((unsigned char *) read_buffer, | 4147 | ? multibyte_chars_in_text ((unsigned char *)read_buffer, nbytes) |
| 3840 | nbytes) | 4148 | : nbytes); |
| 3841 | : nbytes); | 4149 | Lisp_Object result; |
| 3842 | 4150 | if (uninterned_symbol) | |
| 3843 | if (uninterned_symbol) | 4151 | { |
| 3844 | { | 4152 | Lisp_Object name |
| 3845 | Lisp_Object name | 4153 | = (!NILP (Vpurify_flag) |
| 3846 | = ((! NILP (Vpurify_flag) | 4154 | ? make_pure_string (read_buffer, nchars, nbytes, multibyte) |
| 3847 | ? make_pure_string : make_specified_string) | 4155 | : make_specified_string (read_buffer, nchars, nbytes, |
| 3848 | (read_buffer, nchars, nbytes, multibyte)); | 4156 | multibyte)); |
| 3849 | result = Fmake_symbol (name); | 4157 | result = Fmake_symbol (name); |
| 3850 | } | 4158 | } |
| 3851 | else | 4159 | else |
| 3852 | { | 4160 | { |
| 3853 | /* Don't create the string object for the name unless | 4161 | /* Don't create the string object for the name unless |
| 3854 | we're going to retain it in a new symbol. | 4162 | we're going to retain it in a new symbol. |
| 3855 | 4163 | ||
| 3856 | Like intern_1 but supports multibyte names. */ | 4164 | Like intern_1 but supports multibyte names. */ |
| 3857 | Lisp_Object obarray = check_obarray (Vobarray); | 4165 | Lisp_Object obarray = check_obarray (Vobarray); |
| 3858 | 4166 | ||
| 3859 | char* longhand = NULL; | 4167 | char *longhand = NULL; |
| 3860 | ptrdiff_t longhand_chars = 0; | 4168 | ptrdiff_t longhand_chars = 0; |
| 3861 | ptrdiff_t longhand_bytes = 0; | 4169 | ptrdiff_t longhand_bytes = 0; |
| 3862 | 4170 | ||
| 3863 | Lisp_Object tem; | 4171 | Lisp_Object found; |
| 3864 | if (skip_shorthand | 4172 | if (skip_shorthand |
| 3865 | /* The following ASCII characters are used in the | 4173 | /* We exempt characters used in the "core" Emacs Lisp |
| 3866 | only "core" Emacs Lisp symbols that are comprised | 4174 | symbols that are comprised entirely of characters |
| 3867 | entirely of characters that have the 'symbol | 4175 | that have the 'symbol constituent' syntax from |
| 3868 | constituent' syntax. We exempt them from | 4176 | transforming according to shorthands. */ |
| 3869 | transforming according to shorthands. */ | 4177 | || symbol_char_span (read_buffer) >= nbytes) |
| 3870 | || strspn (read_buffer, "^*+-/<=>_|") >= nbytes) | 4178 | found = oblookup (obarray, read_buffer, nchars, nbytes); |
| 3871 | tem = oblookup (obarray, read_buffer, nchars, nbytes); | 4179 | else |
| 3872 | else | 4180 | found = oblookup_considering_shorthand (obarray, read_buffer, |
| 3873 | tem = oblookup_considering_shorthand (obarray, read_buffer, | ||
| 3874 | nchars, nbytes, &longhand, | 4181 | nchars, nbytes, &longhand, |
| 3875 | &longhand_chars, | 4182 | &longhand_chars, |
| 3876 | &longhand_bytes); | 4183 | &longhand_bytes); |
| 3877 | 4184 | ||
| 3878 | if (SYMBOLP (tem)) | 4185 | if (SYMBOLP (found)) |
| 3879 | result = tem; | 4186 | result = found; |
| 3880 | else if (longhand) | 4187 | else if (longhand) |
| 3881 | { | 4188 | { |
| 3882 | Lisp_Object name | 4189 | Lisp_Object name = make_specified_string (longhand, |
| 3883 | = make_specified_string (longhand, longhand_chars, | 4190 | longhand_chars, |
| 3884 | longhand_bytes, multibyte); | 4191 | longhand_bytes, |
| 3885 | xfree (longhand); | 4192 | multibyte); |
| 3886 | result = intern_driver (name, obarray, tem); | 4193 | xfree (longhand); |
| 3887 | } | 4194 | result = intern_driver (name, obarray, found); |
| 3888 | else | 4195 | } |
| 3889 | { | 4196 | else |
| 3890 | Lisp_Object name | 4197 | { |
| 3891 | = make_specified_string (read_buffer, nchars, nbytes, | 4198 | Lisp_Object name = make_specified_string (read_buffer, nchars, |
| 3892 | multibyte); | 4199 | nbytes, multibyte); |
| 3893 | result = intern_driver (name, obarray, tem); | 4200 | result = intern_driver (name, obarray, found); |
| 3894 | } | 4201 | } |
| 3895 | } | 4202 | } |
| 3896 | if (locate_syms | 4203 | if (locate_syms && !NILP (result)) |
| 3897 | && !NILP (result) | 4204 | result = build_symbol_with_pos (result, |
| 3898 | ) | 4205 | make_fixnum (start_position)); |
| 3899 | result = build_symbol_with_pos (result, | ||
| 3900 | make_fixnum (start_position)); | ||
| 3901 | 4206 | ||
| 3902 | return unbind_to (count, result); | 4207 | obj = result; |
| 3903 | } | 4208 | break; |
| 3904 | } | 4209 | } |
| 3905 | } | 4210 | } |
| 4211 | |||
| 4212 | /* We have read an object in `obj'. Use the stack to decide what to | ||
| 4213 | do with it. */ | ||
| 4214 | while (rdstack.sp > base_sp) | ||
| 4215 | { | ||
| 4216 | struct read_stack_entry *e = read_stack_top (); | ||
| 4217 | switch (e->type) | ||
| 4218 | { | ||
| 4219 | case RE_list_start: | ||
| 4220 | e->type = RE_list; | ||
| 4221 | e->u.list.head = e->u.list.tail = Fcons (obj, Qnil); | ||
| 4222 | goto read_obj; | ||
| 4223 | |||
| 4224 | case RE_list: | ||
| 4225 | { | ||
| 4226 | Lisp_Object tl = Fcons (obj, Qnil); | ||
| 4227 | XSETCDR (e->u.list.tail, tl); | ||
| 4228 | e->u.list.tail = tl; | ||
| 4229 | goto read_obj; | ||
| 4230 | } | ||
| 4231 | |||
| 4232 | case RE_list_dot: | ||
| 4233 | { | ||
| 4234 | skip_space_and_comments (readcharfun); | ||
| 4235 | int ch = READCHAR; | ||
| 4236 | if (ch != ')') | ||
| 4237 | invalid_syntax ("expected )", readcharfun); | ||
| 4238 | XSETCDR (e->u.list.tail, obj); | ||
| 4239 | read_stack_pop (); | ||
| 4240 | obj = e->u.list.head; | ||
| 4241 | break; | ||
| 4242 | } | ||
| 4243 | |||
| 4244 | case RE_vector: | ||
| 4245 | case RE_record: | ||
| 4246 | case RE_char_table: | ||
| 4247 | case RE_sub_char_table: | ||
| 4248 | case RE_byte_code: | ||
| 4249 | case RE_string_props: | ||
| 4250 | e->u.vector.elems = Fcons (obj, e->u.vector.elems); | ||
| 4251 | goto read_obj; | ||
| 4252 | |||
| 4253 | case RE_special: | ||
| 4254 | read_stack_pop (); | ||
| 4255 | obj = list2 (e->u.special.symbol, obj); | ||
| 4256 | break; | ||
| 4257 | |||
| 4258 | case RE_numbered: | ||
| 4259 | { | ||
| 4260 | read_stack_pop (); | ||
| 4261 | Lisp_Object placeholder = e->u.numbered.placeholder; | ||
| 4262 | if (CONSP (obj)) | ||
| 4263 | { | ||
| 4264 | if (BASE_EQ (obj, placeholder)) | ||
| 4265 | /* Catch silly games like #1=#1# */ | ||
| 4266 | invalid_syntax ("nonsensical self-reference", readcharfun); | ||
| 4267 | |||
| 4268 | /* Optimisation: since the placeholder is already | ||
| 4269 | a cons, repurpose it as the actual value. | ||
| 4270 | This allows us to skip the substitution below, | ||
| 4271 | since the placeholder is already referenced | ||
| 4272 | inside OBJ at the appropriate places. */ | ||
| 4273 | Fsetcar (placeholder, XCAR (obj)); | ||
| 4274 | Fsetcdr (placeholder, XCDR (obj)); | ||
| 4275 | |||
| 4276 | struct Lisp_Hash_Table *h2 | ||
| 4277 | = XHASH_TABLE (read_objects_completed); | ||
| 4278 | Lisp_Object hash; | ||
| 4279 | ptrdiff_t i = hash_lookup (h2, placeholder, &hash); | ||
| 4280 | eassert (i < 0); | ||
| 4281 | hash_put (h2, placeholder, Qnil, hash); | ||
| 4282 | obj = placeholder; | ||
| 4283 | } | ||
| 4284 | else | ||
| 4285 | { | ||
| 4286 | /* If it can be recursive, remember it for future | ||
| 4287 | substitutions. */ | ||
| 4288 | if (!SYMBOLP (obj) && !NUMBERP (obj) | ||
| 4289 | && !(STRINGP (obj) && !string_intervals (obj))) | ||
| 4290 | { | ||
| 4291 | struct Lisp_Hash_Table *h2 | ||
| 4292 | = XHASH_TABLE (read_objects_completed); | ||
| 4293 | Lisp_Object hash; | ||
| 4294 | ptrdiff_t i = hash_lookup (h2, obj, &hash); | ||
| 4295 | eassert (i < 0); | ||
| 4296 | hash_put (h2, obj, Qnil, hash); | ||
| 4297 | } | ||
| 4298 | |||
| 4299 | /* Now put it everywhere the placeholder was... */ | ||
| 4300 | Flread__substitute_object_in_subtree (obj, placeholder, | ||
| 4301 | read_objects_completed); | ||
| 4302 | |||
| 4303 | /* ...and #n# will use the real value from now on. */ | ||
| 4304 | struct Lisp_Hash_Table *h = XHASH_TABLE (read_objects_map); | ||
| 4305 | Lisp_Object hash; | ||
| 4306 | ptrdiff_t i = hash_lookup (h, e->u.numbered.number, &hash); | ||
| 4307 | eassert (i >= 0); | ||
| 4308 | set_hash_value_slot (h, i, obj); | ||
| 4309 | } | ||
| 4310 | break; | ||
| 4311 | } | ||
| 4312 | } | ||
| 4313 | } | ||
| 4314 | |||
| 4315 | return unbind_to (count, obj); | ||
| 3906 | } | 4316 | } |
| 4317 | |||
| 3907 | 4318 | ||
| 3908 | DEFUN ("lread--substitute-object-in-subtree", | 4319 | DEFUN ("lread--substitute-object-in-subtree", |
| 3909 | Flread__substitute_object_in_subtree, | 4320 | Flread__substitute_object_in_subtree, |
| @@ -4150,214 +4561,6 @@ string_to_number (char const *string, int base, ptrdiff_t *plen) | |||
| 4150 | } | 4561 | } |
| 4151 | 4562 | ||
| 4152 | 4563 | ||
| 4153 | static Lisp_Object | ||
| 4154 | read_vector (Lisp_Object readcharfun, bool bytecodeflag, bool locate_syms) | ||
| 4155 | { | ||
| 4156 | Lisp_Object tem = read_list (1, readcharfun, locate_syms); | ||
| 4157 | ptrdiff_t size = list_length (tem); | ||
| 4158 | Lisp_Object vector = make_nil_vector (size); | ||
| 4159 | |||
| 4160 | /* Avoid accessing past the end of a vector if the vector is too | ||
| 4161 | small to be valid for bytecode. */ | ||
| 4162 | bytecodeflag &= COMPILED_STACK_DEPTH < size; | ||
| 4163 | |||
| 4164 | Lisp_Object *ptr = XVECTOR (vector)->contents; | ||
| 4165 | for (ptrdiff_t i = 0; i < size; i++) | ||
| 4166 | { | ||
| 4167 | Lisp_Object item = Fcar (tem); | ||
| 4168 | /* If `load-force-doc-strings' is t when reading a lazily-loaded | ||
| 4169 | bytecode object, the docstring containing the bytecode and | ||
| 4170 | constants values must be treated as unibyte and passed to | ||
| 4171 | Fread, to get the actual bytecode string and constants vector. */ | ||
| 4172 | if (bytecodeflag && load_force_doc_strings) | ||
| 4173 | { | ||
| 4174 | if (i == COMPILED_BYTECODE) | ||
| 4175 | { | ||
| 4176 | if (!STRINGP (item)) | ||
| 4177 | error ("Invalid byte code"); | ||
| 4178 | |||
| 4179 | /* Delay handling the bytecode slot until we know whether | ||
| 4180 | it is lazily-loaded (we can tell by whether the | ||
| 4181 | constants slot is nil). */ | ||
| 4182 | ASET (vector, COMPILED_CONSTANTS, item); | ||
| 4183 | item = Qnil; | ||
| 4184 | } | ||
| 4185 | else if (i == COMPILED_CONSTANTS) | ||
| 4186 | { | ||
| 4187 | Lisp_Object bytestr = ptr[COMPILED_CONSTANTS]; | ||
| 4188 | |||
| 4189 | if (NILP (item)) | ||
| 4190 | { | ||
| 4191 | /* Coerce string to unibyte (like string-as-unibyte, | ||
| 4192 | but without generating extra garbage and | ||
| 4193 | guaranteeing no change in the contents). */ | ||
| 4194 | STRING_SET_CHARS (bytestr, SBYTES (bytestr)); | ||
| 4195 | STRING_SET_UNIBYTE (bytestr); | ||
| 4196 | |||
| 4197 | item = Fread (Fcons (bytestr, readcharfun)); | ||
| 4198 | if (!CONSP (item)) | ||
| 4199 | error ("Invalid byte code"); | ||
| 4200 | |||
| 4201 | struct Lisp_Cons *otem = XCONS (item); | ||
| 4202 | bytestr = XCAR (item); | ||
| 4203 | item = XCDR (item); | ||
| 4204 | free_cons (otem); | ||
| 4205 | } | ||
| 4206 | |||
| 4207 | /* Now handle the bytecode slot. */ | ||
| 4208 | ASET (vector, COMPILED_BYTECODE, bytestr); | ||
| 4209 | } | ||
| 4210 | else if (i == COMPILED_DOC_STRING | ||
| 4211 | && STRINGP (item) | ||
| 4212 | && ! STRING_MULTIBYTE (item)) | ||
| 4213 | { | ||
| 4214 | if (EQ (readcharfun, Qget_emacs_mule_file_char)) | ||
| 4215 | item = Fdecode_coding_string (item, Qemacs_mule, Qnil, Qnil); | ||
| 4216 | else | ||
| 4217 | item = Fstring_as_multibyte (item); | ||
| 4218 | } | ||
| 4219 | } | ||
| 4220 | ASET (vector, i, item); | ||
| 4221 | struct Lisp_Cons *otem = XCONS (tem); | ||
| 4222 | tem = Fcdr (tem); | ||
| 4223 | free_cons (otem); | ||
| 4224 | } | ||
| 4225 | return vector; | ||
| 4226 | } | ||
| 4227 | |||
| 4228 | /* FLAG means check for ']' to terminate rather than ')' and '.'. | ||
| 4229 | LOCATE_SYMS true means read symbol occurrencess as symbols with | ||
| 4230 | position. */ | ||
| 4231 | |||
| 4232 | static Lisp_Object | ||
| 4233 | read_list (bool flag, Lisp_Object readcharfun, bool locate_syms) | ||
| 4234 | { | ||
| 4235 | Lisp_Object val, tail; | ||
| 4236 | Lisp_Object elt, tem; | ||
| 4237 | /* 0 is the normal case. | ||
| 4238 | 1 means this list is a doc reference; replace it with the number 0. | ||
| 4239 | 2 means this list is a doc reference; replace it with the doc string. */ | ||
| 4240 | int doc_reference = 0; | ||
| 4241 | |||
| 4242 | /* Initialize this to 1 if we are reading a list. */ | ||
| 4243 | bool first_in_list = flag <= 0; | ||
| 4244 | |||
| 4245 | val = Qnil; | ||
| 4246 | tail = Qnil; | ||
| 4247 | |||
| 4248 | while (1) | ||
| 4249 | { | ||
| 4250 | int ch; | ||
| 4251 | elt = read1 (readcharfun, &ch, first_in_list, locate_syms); | ||
| 4252 | |||
| 4253 | first_in_list = 0; | ||
| 4254 | |||
| 4255 | /* While building, if the list starts with #$, treat it specially. */ | ||
| 4256 | if (EQ (elt, Vload_file_name) | ||
| 4257 | && ! NILP (elt)) | ||
| 4258 | { | ||
| 4259 | if (!NILP (Vpurify_flag)) | ||
| 4260 | doc_reference = 0; | ||
| 4261 | else if (load_force_doc_strings) | ||
| 4262 | doc_reference = 2; | ||
| 4263 | } | ||
| 4264 | if (ch) | ||
| 4265 | { | ||
| 4266 | if (flag > 0) | ||
| 4267 | { | ||
| 4268 | if (ch == ']') | ||
| 4269 | return val; | ||
| 4270 | invalid_syntax (") or . in a vector", readcharfun); | ||
| 4271 | } | ||
| 4272 | if (ch == ')') | ||
| 4273 | return val; | ||
| 4274 | if (ch == '.') | ||
| 4275 | { | ||
| 4276 | if (!NILP (tail)) | ||
| 4277 | XSETCDR (tail, read0 (readcharfun, locate_syms)); | ||
| 4278 | else | ||
| 4279 | val = read0 (readcharfun, locate_syms); | ||
| 4280 | read1 (readcharfun, &ch, 0, locate_syms); | ||
| 4281 | |||
| 4282 | if (ch == ')') | ||
| 4283 | { | ||
| 4284 | if (doc_reference == 2 && FIXNUMP (XCDR (val))) | ||
| 4285 | { | ||
| 4286 | char *saved = NULL; | ||
| 4287 | file_offset saved_position; | ||
| 4288 | /* Get a doc string from the file we are loading. | ||
| 4289 | If it's in saved_doc_string, get it from there. | ||
| 4290 | |||
| 4291 | Here, we don't know if the string is a | ||
| 4292 | bytecode string or a doc string. As a | ||
| 4293 | bytecode string must be unibyte, we always | ||
| 4294 | return a unibyte string. If it is actually a | ||
| 4295 | doc string, caller must make it | ||
| 4296 | multibyte. */ | ||
| 4297 | |||
| 4298 | /* Position is negative for user variables. */ | ||
| 4299 | EMACS_INT pos = eabs (XFIXNUM (XCDR (val))); | ||
| 4300 | if (pos >= saved_doc_string_position | ||
| 4301 | && pos < (saved_doc_string_position | ||
| 4302 | + saved_doc_string_length)) | ||
| 4303 | { | ||
| 4304 | saved = saved_doc_string; | ||
| 4305 | saved_position = saved_doc_string_position; | ||
| 4306 | } | ||
| 4307 | /* Look in prev_saved_doc_string the same way. */ | ||
| 4308 | else if (pos >= prev_saved_doc_string_position | ||
| 4309 | && pos < (prev_saved_doc_string_position | ||
| 4310 | + prev_saved_doc_string_length)) | ||
| 4311 | { | ||
| 4312 | saved = prev_saved_doc_string; | ||
| 4313 | saved_position = prev_saved_doc_string_position; | ||
| 4314 | } | ||
| 4315 | if (saved) | ||
| 4316 | { | ||
| 4317 | ptrdiff_t start = pos - saved_position; | ||
| 4318 | ptrdiff_t from, to; | ||
| 4319 | |||
| 4320 | /* Process quoting with ^A, | ||
| 4321 | and find the end of the string, | ||
| 4322 | which is marked with ^_ (037). */ | ||
| 4323 | for (from = start, to = start; | ||
| 4324 | saved[from] != 037;) | ||
| 4325 | { | ||
| 4326 | int c = saved[from++]; | ||
| 4327 | if (c == 1) | ||
| 4328 | { | ||
| 4329 | c = saved[from++]; | ||
| 4330 | saved[to++] = (c == 1 ? c | ||
| 4331 | : c == '0' ? 0 | ||
| 4332 | : c == '_' ? 037 | ||
| 4333 | : c); | ||
| 4334 | } | ||
| 4335 | else | ||
| 4336 | saved[to++] = c; | ||
| 4337 | } | ||
| 4338 | |||
| 4339 | return make_unibyte_string (saved + start, | ||
| 4340 | to - start); | ||
| 4341 | } | ||
| 4342 | else | ||
| 4343 | return get_doc_string (val, 1, 0); | ||
| 4344 | } | ||
| 4345 | |||
| 4346 | return val; | ||
| 4347 | } | ||
| 4348 | invalid_syntax (". in wrong context", readcharfun); | ||
| 4349 | } | ||
| 4350 | invalid_syntax ("] in a list", readcharfun); | ||
| 4351 | } | ||
| 4352 | tem = list1 (elt); | ||
| 4353 | if (!NILP (tail)) | ||
| 4354 | XSETCDR (tail, tem); | ||
| 4355 | else | ||
| 4356 | val = tem; | ||
| 4357 | tail = tem; | ||
| 4358 | } | ||
| 4359 | } | ||
| 4360 | |||
| 4361 | static Lisp_Object initial_obarray; | 4564 | static Lisp_Object initial_obarray; |
| 4362 | 4565 | ||
| 4363 | /* `oblookup' stores the bucket number here, for the sake of Funintern. */ | 4566 | /* `oblookup' stores the bucket number here, for the sake of Funintern. */ |
| @@ -4464,7 +4667,7 @@ define_symbol (Lisp_Object sym, char const *str) | |||
| 4464 | 4667 | ||
| 4465 | /* Qunbound is uninterned, so that it's not confused with any symbol | 4668 | /* Qunbound is uninterned, so that it's not confused with any symbol |
| 4466 | 'unbound' created by a Lisp program. */ | 4669 | 'unbound' created by a Lisp program. */ |
| 4467 | if (! EQ (sym, Qunbound)) | 4670 | if (! BASE_EQ (sym, Qunbound)) |
| 4468 | { | 4671 | { |
| 4469 | Lisp_Object bucket = oblookup (initial_obarray, str, len, len); | 4672 | Lisp_Object bucket = oblookup (initial_obarray, str, len, len); |
| 4470 | eassert (FIXNUMP (bucket)); | 4673 | eassert (FIXNUMP (bucket)); |