diff options
| author | Mattias EngdegÄrd | 2022-06-02 11:46:18 +0200 |
|---|---|---|
| committer | Mattias EngdegÄrd | 2022-06-02 16:57:02 +0200 |
| commit | 52e527a02f40686f355d18ab2ba2d1d7c9fa0fbc (patch) | |
| tree | 9ab242f73ebfc7c55bc93ea89dc986bc248548e6 | |
| parent | 4bacd2a64575ccd55fd9ef8b4648f440243d597a (diff) | |
| download | emacs-52e527a02f40686f355d18ab2ba2d1d7c9fa0fbc.tar.gz emacs-52e527a02f40686f355d18ab2ba2d1d7c9fa0fbc.zip | |
Make ?\LF generate 10, not -1 (bug#55738)
The old -1 value was an artefact of the reader implementation.
* src/lread.c (read_escape): Remove the `stringp` argument; assume
character literal syntax. Never return -1.
(read_string_literal): Handle string-specific escape semantics here
and simplify.
* test/src/lread-tests.el (lread-escaped-lf): New test.
| -rw-r--r-- | src/lread.c | 60 | ||||
| -rw-r--r-- | test/src/lread-tests.el | 5 |
2 files changed, 34 insertions, 31 deletions
diff --git a/src/lread.c b/src/lread.c index 52fc0fff307..4b7d38a8e6c 100644 --- a/src/lread.c +++ b/src/lread.c | |||
| @@ -2633,7 +2633,7 @@ enum { UNICODE_CHARACTER_NAME_LENGTH_BOUND = 200 }; | |||
| 2633 | If the escape sequence forces unibyte, return eight-bit char. */ | 2633 | If the escape sequence forces unibyte, return eight-bit char. */ |
| 2634 | 2634 | ||
| 2635 | static int | 2635 | static int |
| 2636 | read_escape (Lisp_Object readcharfun, bool stringp) | 2636 | read_escape (Lisp_Object readcharfun) |
| 2637 | { | 2637 | { |
| 2638 | int c = READCHAR; | 2638 | int c = READCHAR; |
| 2639 | /* \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 |
| @@ -2663,12 +2663,6 @@ read_escape (Lisp_Object readcharfun, bool stringp) | |||
| 2663 | return '\t'; | 2663 | return '\t'; |
| 2664 | case 'v': | 2664 | case 'v': |
| 2665 | return '\v'; | 2665 | return '\v'; |
| 2666 | case '\n': | ||
| 2667 | return -1; | ||
| 2668 | case ' ': | ||
| 2669 | if (stringp) | ||
| 2670 | return -1; | ||
| 2671 | return ' '; | ||
| 2672 | 2666 | ||
| 2673 | case 'M': | 2667 | case 'M': |
| 2674 | c = READCHAR; | 2668 | c = READCHAR; |
| @@ -2676,7 +2670,7 @@ read_escape (Lisp_Object readcharfun, bool stringp) | |||
| 2676 | error ("Invalid escape character syntax"); | 2670 | error ("Invalid escape character syntax"); |
| 2677 | c = READCHAR; | 2671 | c = READCHAR; |
| 2678 | if (c == '\\') | 2672 | if (c == '\\') |
| 2679 | c = read_escape (readcharfun, 0); | 2673 | c = read_escape (readcharfun); |
| 2680 | return c | meta_modifier; | 2674 | return c | meta_modifier; |
| 2681 | 2675 | ||
| 2682 | case 'S': | 2676 | case 'S': |
| @@ -2685,7 +2679,7 @@ read_escape (Lisp_Object readcharfun, bool stringp) | |||
| 2685 | error ("Invalid escape character syntax"); | 2679 | error ("Invalid escape character syntax"); |
| 2686 | c = READCHAR; | 2680 | c = READCHAR; |
| 2687 | if (c == '\\') | 2681 | if (c == '\\') |
| 2688 | c = read_escape (readcharfun, 0); | 2682 | c = read_escape (readcharfun); |
| 2689 | return c | shift_modifier; | 2683 | return c | shift_modifier; |
| 2690 | 2684 | ||
| 2691 | case 'H': | 2685 | case 'H': |
| @@ -2694,7 +2688,7 @@ read_escape (Lisp_Object readcharfun, bool stringp) | |||
| 2694 | error ("Invalid escape character syntax"); | 2688 | error ("Invalid escape character syntax"); |
| 2695 | c = READCHAR; | 2689 | c = READCHAR; |
| 2696 | if (c == '\\') | 2690 | if (c == '\\') |
| 2697 | c = read_escape (readcharfun, 0); | 2691 | c = read_escape (readcharfun); |
| 2698 | return c | hyper_modifier; | 2692 | return c | hyper_modifier; |
| 2699 | 2693 | ||
| 2700 | case 'A': | 2694 | case 'A': |
| @@ -2703,19 +2697,19 @@ read_escape (Lisp_Object readcharfun, bool stringp) | |||
| 2703 | error ("Invalid escape character syntax"); | 2697 | error ("Invalid escape character syntax"); |
| 2704 | c = READCHAR; | 2698 | c = READCHAR; |
| 2705 | if (c == '\\') | 2699 | if (c == '\\') |
| 2706 | c = read_escape (readcharfun, 0); | 2700 | c = read_escape (readcharfun); |
| 2707 | return c | alt_modifier; | 2701 | return c | alt_modifier; |
| 2708 | 2702 | ||
| 2709 | case 's': | 2703 | case 's': |
| 2710 | c = READCHAR; | 2704 | c = READCHAR; |
| 2711 | if (stringp || c != '-') | 2705 | if (c != '-') |
| 2712 | { | 2706 | { |
| 2713 | UNREAD (c); | 2707 | UNREAD (c); |
| 2714 | return ' '; | 2708 | return ' '; |
| 2715 | } | 2709 | } |
| 2716 | c = READCHAR; | 2710 | c = READCHAR; |
| 2717 | if (c == '\\') | 2711 | if (c == '\\') |
| 2718 | c = read_escape (readcharfun, 0); | 2712 | c = read_escape (readcharfun); |
| 2719 | return c | super_modifier; | 2713 | return c | super_modifier; |
| 2720 | 2714 | ||
| 2721 | case 'C': | 2715 | case 'C': |
| @@ -2726,7 +2720,7 @@ read_escape (Lisp_Object readcharfun, bool stringp) | |||
| 2726 | case '^': | 2720 | case '^': |
| 2727 | c = READCHAR; | 2721 | c = READCHAR; |
| 2728 | if (c == '\\') | 2722 | if (c == '\\') |
| 2729 | c = read_escape (readcharfun, 0); | 2723 | c = read_escape (readcharfun); |
| 2730 | if ((c & ~CHAR_MODIFIER_MASK) == '?') | 2724 | if ((c & ~CHAR_MODIFIER_MASK) == '?') |
| 2731 | return 0177 | (c & CHAR_MODIFIER_MASK); | 2725 | return 0177 | (c & CHAR_MODIFIER_MASK); |
| 2732 | else if (! ASCII_CHAR_P ((c & ~CHAR_MODIFIER_MASK))) | 2726 | else if (! ASCII_CHAR_P ((c & ~CHAR_MODIFIER_MASK))) |
| @@ -3011,7 +3005,7 @@ read_char_literal (Lisp_Object readcharfun) | |||
| 3011 | } | 3005 | } |
| 3012 | 3006 | ||
| 3013 | if (ch == '\\') | 3007 | if (ch == '\\') |
| 3014 | ch = read_escape (readcharfun, 0); | 3008 | ch = read_escape (readcharfun); |
| 3015 | 3009 | ||
| 3016 | int modifiers = ch & CHAR_MODIFIER_MASK; | 3010 | int modifiers = ch & CHAR_MODIFIER_MASK; |
| 3017 | ch &= ~CHAR_MODIFIER_MASK; | 3011 | ch &= ~CHAR_MODIFIER_MASK; |
| @@ -3065,14 +3059,24 @@ read_string_literal (char stackbuf[VLA_ELEMS (stackbufsize)], | |||
| 3065 | 3059 | ||
| 3066 | if (ch == '\\') | 3060 | if (ch == '\\') |
| 3067 | { | 3061 | { |
| 3068 | ch = read_escape (readcharfun, 1); | 3062 | /* First apply string-specific escape rules: */ |
| 3069 | 3063 | ch = READCHAR; | |
| 3070 | /* CH is -1 if \ newline or \ space has just been seen. */ | 3064 | switch (ch) |
| 3071 | if (ch == -1) | ||
| 3072 | { | 3065 | { |
| 3066 | case 's': | ||
| 3067 | /* `\s' is always a space in strings. */ | ||
| 3068 | ch = ' '; | ||
| 3069 | break; | ||
| 3070 | case ' ': | ||
| 3071 | case '\n': | ||
| 3072 | /* `\SPC' and `\LF' generate no characters at all. */ | ||
| 3073 | if (p == read_buffer) | 3073 | if (p == read_buffer) |
| 3074 | cancel = true; | 3074 | cancel = true; |
| 3075 | continue; | 3075 | continue; |
| 3076 | default: | ||
| 3077 | UNREAD (ch); | ||
| 3078 | ch = read_escape (readcharfun); | ||
| 3079 | break; | ||
| 3076 | } | 3080 | } |
| 3077 | 3081 | ||
| 3078 | int modifiers = ch & CHAR_MODIFIER_MASK; | 3082 | int modifiers = ch & CHAR_MODIFIER_MASK; |
| @@ -3084,19 +3088,13 @@ read_string_literal (char stackbuf[VLA_ELEMS (stackbufsize)], | |||
| 3084 | force_multibyte = true; | 3088 | force_multibyte = true; |
| 3085 | else /* I.e. ASCII_CHAR_P (ch). */ | 3089 | else /* I.e. ASCII_CHAR_P (ch). */ |
| 3086 | { | 3090 | { |
| 3087 | /* Allow `\C- ' and `\C-?'. */ | 3091 | /* Allow `\C-SPC' and `\^SPC'. This is done here because |
| 3088 | if (modifiers == CHAR_CTL) | 3092 | the literals ?\C-SPC and ?\^SPC (rather inconsistently) |
| 3093 | yield (' ' | CHAR_CTL); see bug#55738. */ | ||
| 3094 | if (modifiers == CHAR_CTL && ch == ' ') | ||
| 3089 | { | 3095 | { |
| 3090 | if (ch == ' ') | 3096 | ch = 0; |
| 3091 | { | 3097 | modifiers = 0; |
| 3092 | ch = 0; | ||
| 3093 | modifiers = 0; | ||
| 3094 | } | ||
| 3095 | else if (ch == '?') | ||
| 3096 | { | ||
| 3097 | ch = 127; | ||
| 3098 | modifiers = 0; | ||
| 3099 | } | ||
| 3100 | } | 3098 | } |
| 3101 | if (modifiers & CHAR_SHIFT) | 3099 | if (modifiers & CHAR_SHIFT) |
| 3102 | { | 3100 | { |
diff --git a/test/src/lread-tests.el b/test/src/lread-tests.el index 47351c1d116..99eec9d5487 100644 --- a/test/src/lread-tests.el +++ b/test/src/lread-tests.el | |||
| @@ -317,4 +317,9 @@ literals (Bug#20852)." | |||
| 317 | (should (equal (read-from-string "#_") | 317 | (should (equal (read-from-string "#_") |
| 318 | '(## . 2)))) | 318 | '(## . 2)))) |
| 319 | 319 | ||
| 320 | (ert-deftest lread-escaped-lf () | ||
| 321 | ;; ?\LF should produce LF (only inside string literals do we ignore \LF). | ||
| 322 | (should (equal (read-from-string "?\\\n") '(?\n . 3))) | ||
| 323 | (should (equal (read-from-string "\"a\\\nb\"") '("ab" . 6)))) | ||
| 324 | |||
| 320 | ;;; lread-tests.el ends here | 325 | ;;; lread-tests.el ends here |