diff options
| author | Paul Eggert | 2018-10-10 23:17:18 -0700 |
|---|---|---|
| committer | Paul Eggert | 2018-10-10 23:19:42 -0700 |
| commit | 5bd8cfc14d4b0c78c07e65a583f42a10c4cbc06d (patch) | |
| tree | c51b2a470f62679f5e5c3f6f55d90aa0082d0133 | |
| parent | fd3a48fcd8bb212ec12b9b10a79de0ae605ee93b (diff) | |
| download | emacs-5bd8cfc14d4b0c78c07e65a583f42a10c4cbc06d.tar.gz emacs-5bd8cfc14d4b0c78c07e65a583f42a10c4cbc06d.zip | |
Fix mishandling of symbols that look like numbers
* src/bignum.c (make_neg_biguint): New function.
* src/lread.c (read1): Do not mishandle an unquoted symbol
with name equal to something like "1\0x", i.e., a string
of numeric form followed by a NUL byte.
Formerly these symbols were misread as numbers.
(string_to_number): Change last argument from an integer flag
to a pointer to the length. This lets the caller figure out
how much of the prefix was used. All callers changed.
Add a fast path if the integer (sans sign) fits in uintmax_t.
Update comments and simplify now that bignums are present.
* src/print.c (print_object): Fix quoting of symbols that look
like numbers, by relying on string_to_number for the tricky
cases rather than trying to redo its logic, incorrectly. For
example, (read (prin1-to-string '\1e+NaN)) formerly returned
"1e+NaN", which was wrong: a backslash is needed in the output
to prevent it from being read as a NaN. Escape NO_BREAK_SPACE
too, since lread.c treats it like SPACE.
* test/src/print-tests.el (print-read-roundtrip):
Add tests illustrating the abovementioned bugs.
| -rw-r--r-- | src/bignum.c | 10 | ||||
| -rw-r--r-- | src/data.c | 2 | ||||
| -rw-r--r-- | src/lisp.h | 5 | ||||
| -rw-r--r-- | src/lread.c | 100 | ||||
| -rw-r--r-- | src/print.c | 49 | ||||
| -rw-r--r-- | src/process.c | 7 | ||||
| -rw-r--r-- | test/src/print-tests.el | 16 |
7 files changed, 99 insertions, 90 deletions
diff --git a/src/bignum.c b/src/bignum.c index 0ab8de3ab7a..e3db0377a53 100644 --- a/src/bignum.c +++ b/src/bignum.c | |||
| @@ -117,6 +117,16 @@ make_biguint (uintmax_t n) | |||
| 117 | return make_bignum (); | 117 | return make_bignum (); |
| 118 | } | 118 | } |
| 119 | 119 | ||
| 120 | /* Return a Lisp integer equal to -N, which must not be in fixnum range. */ | ||
| 121 | Lisp_Object | ||
| 122 | make_neg_biguint (uintmax_t n) | ||
| 123 | { | ||
| 124 | eassert (-MOST_NEGATIVE_FIXNUM < n); | ||
| 125 | mpz_set_uintmax (mpz[0], n); | ||
| 126 | mpz_neg (mpz[0], mpz[0]); | ||
| 127 | return make_bignum (); | ||
| 128 | } | ||
| 129 | |||
| 120 | /* Return a Lisp integer with value taken from mpz[0]. | 130 | /* Return a Lisp integer with value taken from mpz[0]. |
| 121 | Set mpz[0] to a junk value. */ | 131 | Set mpz[0] to a junk value. */ |
| 122 | Lisp_Object | 132 | Lisp_Object |
diff --git a/src/data.c b/src/data.c index 5f1d059512d..538081e5c9b 100644 --- a/src/data.c +++ b/src/data.c | |||
| @@ -2796,7 +2796,7 @@ If the base used is not 10, STRING is always parsed as an integer. */) | |||
| 2796 | while (*p == ' ' || *p == '\t') | 2796 | while (*p == ' ' || *p == '\t') |
| 2797 | p++; | 2797 | p++; |
| 2798 | 2798 | ||
| 2799 | Lisp_Object val = string_to_number (p, b, S2N_IGNORE_TRAILING); | 2799 | Lisp_Object val = string_to_number (p, b, 0); |
| 2800 | return NILP (val) ? make_fixnum (0) : val; | 2800 | return NILP (val) ? make_fixnum (0) : val; |
| 2801 | } | 2801 | } |
| 2802 | 2802 | ||
diff --git a/src/lisp.h b/src/lisp.h index 2c20b483cad..5ecc48b025c 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -2506,7 +2506,7 @@ INTEGERP (Lisp_Object x) | |||
| 2506 | return FIXNUMP (x) || BIGNUMP (x); | 2506 | return FIXNUMP (x) || BIGNUMP (x); |
| 2507 | } | 2507 | } |
| 2508 | 2508 | ||
| 2509 | /* Return a Lisp integer with value taken from n. */ | 2509 | /* Return a Lisp integer with value taken from N. */ |
| 2510 | INLINE Lisp_Object | 2510 | INLINE Lisp_Object |
| 2511 | make_int (intmax_t n) | 2511 | make_int (intmax_t n) |
| 2512 | { | 2512 | { |
| @@ -3329,6 +3329,7 @@ extern ptrdiff_t bignum_bufsize (Lisp_Object, int); | |||
| 3329 | extern ptrdiff_t bignum_to_c_string (char *, ptrdiff_t, Lisp_Object, int); | 3329 | extern ptrdiff_t bignum_to_c_string (char *, ptrdiff_t, Lisp_Object, int); |
| 3330 | extern Lisp_Object bignum_to_string (Lisp_Object, int); | 3330 | extern Lisp_Object bignum_to_string (Lisp_Object, int); |
| 3331 | extern Lisp_Object make_bignum_str (char const *, int); | 3331 | extern Lisp_Object make_bignum_str (char const *, int); |
| 3332 | extern Lisp_Object make_neg_biguint (uintmax_t); | ||
| 3332 | extern Lisp_Object double_to_integer (double); | 3333 | extern Lisp_Object double_to_integer (double); |
| 3333 | 3334 | ||
| 3334 | /* Converthe integer NUM to *N. Return true if successful, false | 3335 | /* Converthe integer NUM to *N. Return true if successful, false |
| @@ -3839,7 +3840,7 @@ LOADHIST_ATTACH (Lisp_Object x) | |||
| 3839 | extern int openp (Lisp_Object, Lisp_Object, Lisp_Object, | 3840 | extern int openp (Lisp_Object, Lisp_Object, Lisp_Object, |
| 3840 | Lisp_Object *, Lisp_Object, bool); | 3841 | Lisp_Object *, Lisp_Object, bool); |
| 3841 | enum { S2N_IGNORE_TRAILING = 1 }; | 3842 | enum { S2N_IGNORE_TRAILING = 1 }; |
| 3842 | extern Lisp_Object string_to_number (char const *, int, int); | 3843 | extern Lisp_Object string_to_number (char const *, int, ptrdiff_t *); |
| 3843 | extern void map_obarray (Lisp_Object, void (*) (Lisp_Object, Lisp_Object), | 3844 | extern void map_obarray (Lisp_Object, void (*) (Lisp_Object, Lisp_Object), |
| 3844 | Lisp_Object); | 3845 | Lisp_Object); |
| 3845 | extern void dir_warning (const char *, Lisp_Object); | 3846 | extern void dir_warning (const char *, Lisp_Object); |
diff --git a/src/lread.c b/src/lread.c index 73e38d89954..62616cb6819 100644 --- a/src/lread.c +++ b/src/lread.c | |||
| @@ -2354,12 +2354,14 @@ character_name_to_code (char const *name, ptrdiff_t name_len) | |||
| 2354 | { | 2354 | { |
| 2355 | /* For "U+XXXX", pass the leading '+' to string_to_number to reject | 2355 | /* For "U+XXXX", pass the leading '+' to string_to_number to reject |
| 2356 | monstrosities like "U+-0000". */ | 2356 | monstrosities like "U+-0000". */ |
| 2357 | ptrdiff_t len = name_len - 1; | ||
| 2357 | Lisp_Object code | 2358 | Lisp_Object code |
| 2358 | = (name[0] == 'U' && name[1] == '+' | 2359 | = (name[0] == 'U' && name[1] == '+' |
| 2359 | ? string_to_number (name + 1, 16, 0) | 2360 | ? string_to_number (name + 1, 16, &len) |
| 2360 | : call2 (Qchar_from_name, make_unibyte_string (name, name_len), Qt)); | 2361 | : call2 (Qchar_from_name, make_unibyte_string (name, name_len), Qt)); |
| 2361 | 2362 | ||
| 2362 | if (! RANGED_FIXNUMP (0, code, MAX_UNICODE_CHAR) | 2363 | if (! RANGED_FIXNUMP (0, code, MAX_UNICODE_CHAR) |
| 2364 | || len != name_len - 1 | ||
| 2363 | || char_surrogate_p (XFIXNUM (code))) | 2365 | || char_surrogate_p (XFIXNUM (code))) |
| 2364 | { | 2366 | { |
| 2365 | AUTO_STRING (format, "\\N{%s}"); | 2367 | AUTO_STRING (format, "\\N{%s}"); |
| @@ -3531,12 +3533,14 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 3531 | || strchr ("\"';()[]#`,", c) == NULL)); | 3533 | || strchr ("\"';()[]#`,", c) == NULL)); |
| 3532 | 3534 | ||
| 3533 | *p = 0; | 3535 | *p = 0; |
| 3536 | ptrdiff_t nbytes = p - read_buffer; | ||
| 3534 | UNREAD (c); | 3537 | UNREAD (c); |
| 3535 | 3538 | ||
| 3536 | if (!quoted && !uninterned_symbol) | 3539 | if (!quoted && !uninterned_symbol) |
| 3537 | { | 3540 | { |
| 3538 | Lisp_Object result = string_to_number (read_buffer, 10, 0); | 3541 | ptrdiff_t len; |
| 3539 | if (! NILP (result)) | 3542 | Lisp_Object result = string_to_number (read_buffer, 10, &len); |
| 3543 | if (! NILP (result) && len == nbytes) | ||
| 3540 | return unbind_to (count, result); | 3544 | return unbind_to (count, result); |
| 3541 | } | 3545 | } |
| 3542 | if (!quoted && multibyte) | 3546 | if (!quoted && multibyte) |
| @@ -3548,7 +3552,6 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 3548 | } | 3552 | } |
| 3549 | { | 3553 | { |
| 3550 | Lisp_Object result; | 3554 | Lisp_Object result; |
| 3551 | ptrdiff_t nbytes = p - read_buffer; | ||
| 3552 | ptrdiff_t nchars | 3555 | ptrdiff_t nchars |
| 3553 | = (multibyte | 3556 | = (multibyte |
| 3554 | ? multibyte_chars_in_text ((unsigned char *) read_buffer, | 3557 | ? multibyte_chars_in_text ((unsigned char *) read_buffer, |
| @@ -3700,18 +3703,18 @@ substitute_in_interval (INTERVAL interval, void *arg) | |||
| 3700 | } | 3703 | } |
| 3701 | 3704 | ||
| 3702 | 3705 | ||
| 3703 | /* Convert STRING to a number, assuming base BASE. When STRING has | 3706 | /* Convert the initial prefix of STRING to a number, assuming base BASE. |
| 3704 | floating point syntax and BASE is 10, return a nearest float. When | 3707 | If the prefix has floating point syntax and BASE is 10, return a |
| 3705 | STRING has integer syntax, return a fixnum if the integer fits, or | 3708 | nearest float; otherwise, if the prefix has integer syntax, return |
| 3706 | else a bignum. Otherwise, return nil. If FLAGS & | 3709 | the integer; otherwise, return nil. If PLEN, set *PLEN to the |
| 3707 | S2N_IGNORE_TRAILING is nonzero, consider just the longest prefix of | 3710 | length of the numeric prefix if there is one, otherwise *PLEN is |
| 3708 | STRING that has valid syntax. */ | 3711 | unspecified. */ |
| 3709 | 3712 | ||
| 3710 | Lisp_Object | 3713 | Lisp_Object |
| 3711 | string_to_number (char const *string, int base, int flags) | 3714 | string_to_number (char const *string, int base, ptrdiff_t *plen) |
| 3712 | { | 3715 | { |
| 3713 | char const *cp = string; | 3716 | char const *cp = string; |
| 3714 | bool float_syntax = 0; | 3717 | bool float_syntax = false; |
| 3715 | double value = 0; | 3718 | double value = 0; |
| 3716 | 3719 | ||
| 3717 | /* Negate the value ourselves. This treats 0, NaNs, and infinity properly on | 3720 | /* Negate the value ourselves. This treats 0, NaNs, and infinity properly on |
| @@ -3797,49 +3800,46 @@ string_to_number (char const *string, int base, int flags) | |||
| 3797 | || (state & ~INTOVERFLOW) == (LEAD_INT|E_EXP)); | 3800 | || (state & ~INTOVERFLOW) == (LEAD_INT|E_EXP)); |
| 3798 | } | 3801 | } |
| 3799 | 3802 | ||
| 3800 | /* Return nil if the number uses invalid syntax. If FLAGS & | 3803 | if (plen) |
| 3801 | S2N_IGNORE_TRAILING, accept any prefix that matches. Otherwise, | 3804 | *plen = cp - string; |
| 3802 | the entire string must match. */ | ||
| 3803 | if (! (flags & S2N_IGNORE_TRAILING | ||
| 3804 | ? ((state & LEAD_INT) != 0 || float_syntax) | ||
| 3805 | : (!*cp && ((state & ~(INTOVERFLOW | DOT_CHAR)) == LEAD_INT | ||
| 3806 | || float_syntax)))) | ||
| 3807 | return Qnil; | ||
| 3808 | 3805 | ||
| 3809 | /* If the number uses integer and not float syntax, and is in C-language | 3806 | /* Return a float if the number uses float syntax. */ |
| 3810 | range, use its value, preferably as a fixnum. */ | 3807 | if (float_syntax) |
| 3811 | if (leading_digit >= 0 && ! float_syntax) | ||
| 3812 | { | 3808 | { |
| 3813 | if ((state & INTOVERFLOW) == 0 | 3809 | /* Convert to floating point, unless the value is already known |
| 3814 | && n <= (negative ? -MOST_NEGATIVE_FIXNUM : MOST_POSITIVE_FIXNUM)) | 3810 | because it is infinite or a NaN. */ |
| 3815 | { | 3811 | if (! value) |
| 3816 | EMACS_INT signed_n = n; | 3812 | value = atof (string + signedp); |
| 3817 | return make_fixnum (negative ? -signed_n : signed_n); | 3813 | return make_float (negative ? -value : value); |
| 3818 | } | ||
| 3819 | |||
| 3820 | /* Trim any leading "+" and trailing nondigits, then convert to | ||
| 3821 | bignum. */ | ||
| 3822 | string += positive; | ||
| 3823 | if (!*after_digits) | ||
| 3824 | return make_bignum_str (string, base); | ||
| 3825 | ptrdiff_t trimmed_len = after_digits - string; | ||
| 3826 | USE_SAFE_ALLOCA; | ||
| 3827 | char *trimmed = SAFE_ALLOCA (trimmed_len + 1); | ||
| 3828 | memcpy (trimmed, string, trimmed_len); | ||
| 3829 | trimmed[trimmed_len] = '\0'; | ||
| 3830 | Lisp_Object result = make_bignum_str (trimmed, base); | ||
| 3831 | SAFE_FREE (); | ||
| 3832 | return result; | ||
| 3833 | } | 3814 | } |
| 3834 | 3815 | ||
| 3835 | /* Either the number uses float syntax, or it does not fit into a fixnum. | 3816 | /* Return nil if the number uses invalid syntax. */ |
| 3836 | Convert it from string to floating point, unless the value is already | 3817 | if (! (state & LEAD_INT)) |
| 3837 | known because it is an infinity, a NAN, or its absolute value fits in | 3818 | return Qnil; |
| 3838 | uintmax_t. */ | 3819 | |
| 3839 | if (! value) | 3820 | /* Fast path if the integer (san sign) fits in uintmax_t. */ |
| 3840 | value = atof (string + signedp); | 3821 | if (! (state & INTOVERFLOW)) |
| 3822 | { | ||
| 3823 | if (!negative) | ||
| 3824 | return make_uint (n); | ||
| 3825 | if (-MOST_NEGATIVE_FIXNUM < n) | ||
| 3826 | return make_neg_biguint (n); | ||
| 3827 | EMACS_INT signed_n = n; | ||
| 3828 | return make_fixnum (-signed_n); | ||
| 3829 | } | ||
| 3841 | 3830 | ||
| 3842 | return make_float (negative ? -value : value); | 3831 | /* Trim any leading "+" and trailing nondigits, then return a bignum. */ |
| 3832 | string += positive; | ||
| 3833 | if (!*after_digits) | ||
| 3834 | return make_bignum_str (string, base); | ||
| 3835 | ptrdiff_t trimmed_len = after_digits - string; | ||
| 3836 | USE_SAFE_ALLOCA; | ||
| 3837 | char *trimmed = SAFE_ALLOCA (trimmed_len + 1); | ||
| 3838 | memcpy (trimmed, string, trimmed_len); | ||
| 3839 | trimmed[trimmed_len] = '\0'; | ||
| 3840 | Lisp_Object result = make_bignum_str (trimmed, base); | ||
| 3841 | SAFE_FREE (); | ||
| 3842 | return result; | ||
| 3843 | } | 3843 | } |
| 3844 | 3844 | ||
| 3845 | 3845 | ||
diff --git a/src/print.c b/src/print.c index c0c90bc7e9a..d15ff97b00c 100644 --- a/src/print.c +++ b/src/print.c | |||
| @@ -1993,39 +1993,17 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag) | |||
| 1993 | 1993 | ||
| 1994 | case Lisp_Symbol: | 1994 | case Lisp_Symbol: |
| 1995 | { | 1995 | { |
| 1996 | bool confusing; | 1996 | Lisp_Object name = SYMBOL_NAME (obj); |
| 1997 | unsigned char *p = SDATA (SYMBOL_NAME (obj)); | 1997 | ptrdiff_t size_byte = SBYTES (name); |
| 1998 | unsigned char *end = p + SBYTES (SYMBOL_NAME (obj)); | 1998 | |
| 1999 | int c; | 1999 | /* Set CONFUSING if NAME looks like a number, calling |
| 2000 | ptrdiff_t i, i_byte; | 2000 | string_to_number for non-obvious cases. */ |
| 2001 | ptrdiff_t size_byte; | 2001 | char *p = SSDATA (name); |
| 2002 | Lisp_Object name; | 2002 | bool signedp = *p == '-' || *p == '+'; |
| 2003 | 2003 | ptrdiff_t len; | |
| 2004 | name = SYMBOL_NAME (obj); | 2004 | bool confusing = ((c_isdigit (p[signedp]) || p[signedp] == '.') |
| 2005 | 2005 | && !NILP (string_to_number (p, 10, &len)) | |
| 2006 | if (p != end && (*p == '-' || *p == '+')) p++; | 2006 | && len == size_byte); |
| 2007 | if (p == end) | ||
| 2008 | confusing = 0; | ||
| 2009 | /* If symbol name begins with a digit, and ends with a digit, | ||
| 2010 | and contains nothing but digits and `e', it could be treated | ||
| 2011 | as a number. So set CONFUSING. | ||
| 2012 | |||
| 2013 | Symbols that contain periods could also be taken as numbers, | ||
| 2014 | but periods are always escaped, so we don't have to worry | ||
| 2015 | about them here. */ | ||
| 2016 | else if (*p >= '0' && *p <= '9' | ||
| 2017 | && end[-1] >= '0' && end[-1] <= '9') | ||
| 2018 | { | ||
| 2019 | while (p != end && ((*p >= '0' && *p <= '9') | ||
| 2020 | /* Needed for \2e10. */ | ||
| 2021 | || *p == 'e' || *p == 'E')) | ||
| 2022 | p++; | ||
| 2023 | confusing = (end == p); | ||
| 2024 | } | ||
| 2025 | else | ||
| 2026 | confusing = 0; | ||
| 2027 | |||
| 2028 | size_byte = SBYTES (name); | ||
| 2029 | 2007 | ||
| 2030 | if (! NILP (Vprint_gensym) | 2008 | if (! NILP (Vprint_gensym) |
| 2031 | && !SYMBOL_INTERNED_IN_INITIAL_OBARRAY_P (obj)) | 2009 | && !SYMBOL_INTERNED_IN_INITIAL_OBARRAY_P (obj)) |
| @@ -2036,10 +2014,12 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag) | |||
| 2036 | break; | 2014 | break; |
| 2037 | } | 2015 | } |
| 2038 | 2016 | ||
| 2039 | for (i = 0, i_byte = 0; i_byte < size_byte;) | 2017 | ptrdiff_t i = 0; |
| 2018 | for (ptrdiff_t i_byte = 0; i_byte < size_byte; ) | ||
| 2040 | { | 2019 | { |
| 2041 | /* Here, we must convert each multi-byte form to the | 2020 | /* Here, we must convert each multi-byte form to the |
| 2042 | corresponding character code before handing it to PRINTCHAR. */ | 2021 | corresponding character code before handing it to PRINTCHAR. */ |
| 2022 | int c; | ||
| 2043 | FETCH_STRING_CHAR_ADVANCE (c, name, i, i_byte); | 2023 | FETCH_STRING_CHAR_ADVANCE (c, name, i, i_byte); |
| 2044 | maybe_quit (); | 2024 | maybe_quit (); |
| 2045 | 2025 | ||
| @@ -2049,6 +2029,7 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag) | |||
| 2049 | || c == ';' || c == '#' || c == '(' || c == ')' | 2029 | || c == ';' || c == '#' || c == '(' || c == ')' |
| 2050 | || c == ',' || c == '.' || c == '`' | 2030 | || c == ',' || c == '.' || c == '`' |
| 2051 | || c == '[' || c == ']' || c == '?' || c <= 040 | 2031 | || c == '[' || c == ']' || c == '?' || c <= 040 |
| 2032 | || c == NO_BREAK_SPACE | ||
| 2052 | || confusing | 2033 | || confusing |
| 2053 | || (i == 1 && confusable_symbol_character_p (c))) | 2034 | || (i == 1 && confusable_symbol_character_p (c))) |
| 2054 | { | 2035 | { |
diff --git a/src/process.c b/src/process.c index a9638dfc2df..6cda4f27acc 100644 --- a/src/process.c +++ b/src/process.c | |||
| @@ -6852,7 +6852,12 @@ SIGCODE may be an integer, or a symbol whose name is a signal name. */) | |||
| 6852 | { | 6852 | { |
| 6853 | Lisp_Object tem = Fget_process (process); | 6853 | Lisp_Object tem = Fget_process (process); |
| 6854 | if (NILP (tem)) | 6854 | if (NILP (tem)) |
| 6855 | tem = string_to_number (SSDATA (process), 10, 0); | 6855 | { |
| 6856 | ptrdiff_t len; | ||
| 6857 | tem = string_to_number (SSDATA (process), 10, &len); | ||
| 6858 | if (NILP (tem) || len != SBYTES (process)) | ||
| 6859 | return Qnil; | ||
| 6860 | } | ||
| 6856 | process = tem; | 6861 | process = tem; |
| 6857 | } | 6862 | } |
| 6858 | else if (!NUMBERP (process)) | 6863 | else if (!NUMBERP (process)) |
diff --git a/test/src/print-tests.el b/test/src/print-tests.el index 091f1aa1afb..78e769f50e9 100644 --- a/test/src/print-tests.el +++ b/test/src/print-tests.el | |||
| @@ -95,8 +95,20 @@ otherwise, use a different charset." | |||
| 95 | "--------\n")))) | 95 | "--------\n")))) |
| 96 | 96 | ||
| 97 | (ert-deftest print-read-roundtrip () | 97 | (ert-deftest print-read-roundtrip () |
| 98 | (let ((sym '\’bar)) | 98 | (let ((syms (list '## '& '* '+ '- '/ '0E '0e '< '= '> 'E 'E0 'NaN '\" |
| 99 | (should (eq (read (prin1-to-string sym)) sym)))) | 99 | '\# '\#x0 '\' '\'\' '\( '\) '\+00 '\, '\-0 '\. '\.0 |
| 100 | '\0 '\0.0 '\0E0 '\0e0 '\1E+ '\1E+NaN '\1e+ '\1e+NaN | ||
| 101 | '\; '\? '\[ '\\ '\] '\` '_ 'a 'e 'e0 'x | ||
| 102 | '{ '| '} '~ : '\’ '\’bar | ||
| 103 | (intern "\t") (intern "\n") (intern " ") | ||
| 104 | (intern "\N{NO-BREAK SPACE}") | ||
| 105 | (intern "\N{ZERO WIDTH SPACE}") | ||
| 106 | (intern "\0")))) | ||
| 107 | (dolist (sym syms) | ||
| 108 | (should (eq (read (prin1-to-string sym)) sym)) | ||
| 109 | (dolist (sym1 syms) | ||
| 110 | (let ((sym2 (intern (concat (symbol-name sym) (symbol-name sym1))))) | ||
| 111 | (should (eq (read (prin1-to-string sym2)) sym2))))))) | ||
| 100 | 112 | ||
| 101 | (ert-deftest print-bignum () | 113 | (ert-deftest print-bignum () |
| 102 | (let* ((str "999999999999999999999999999999999") | 114 | (let* ((str "999999999999999999999999999999999") |