diff options
| author | Lars Ingebrigtsen | 2021-02-01 17:04:17 +0100 |
|---|---|---|
| committer | Lars Ingebrigtsen | 2021-02-01 17:04:17 +0100 |
| commit | e38e7b7bc121b96649518e5e986bba23697abc2d (patch) | |
| tree | 01229b2db2fe4617a2894919e6d09bffa8ef5ba8 /src | |
| parent | 3990716a97f48adc0a77250cdf5a2853f3f7f7e0 (diff) | |
| download | emacs-e38e7b7bc121b96649518e5e986bba23697abc2d.tar.gz emacs-e38e7b7bc121b96649518e5e986bba23697abc2d.zip | |
Make syntax errors say the line/column they appear at
* src/lisp.h: Add count_lines prototype.
* src/lread.c (invalid_syntax_lisp): New function (bug#36970).
(invalid_syntax): Extend function to take a readcharfun parameter.
(read_emacs_mule_char, character_name_to_code): Pass in.
(read_escape, invalid_radix_integer, read1): Ditto.
* src/xdisp.c (count_lines): Add a more succinct shim over
display_count_lines.
Diffstat (limited to 'src')
| -rw-r--r-- | src/lisp.h | 1 | ||||
| -rw-r--r-- | src/lread.c | 100 | ||||
| -rw-r--r-- | src/xdisp.c | 9 |
3 files changed, 70 insertions, 40 deletions
diff --git a/src/lisp.h b/src/lisp.h index f6588685443..409a1e70608 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -3734,6 +3734,7 @@ extern void message_log_maybe_newline (void); | |||
| 3734 | extern void update_echo_area (void); | 3734 | extern void update_echo_area (void); |
| 3735 | extern void truncate_echo_area (ptrdiff_t); | 3735 | extern void truncate_echo_area (ptrdiff_t); |
| 3736 | extern void redisplay (void); | 3736 | extern void redisplay (void); |
| 3737 | extern ptrdiff_t count_lines (ptrdiff_t start_byte, ptrdiff_t end_byte); | ||
| 3737 | 3738 | ||
| 3738 | void set_frame_cursor_types (struct frame *, Lisp_Object); | 3739 | void set_frame_cursor_types (struct frame *, Lisp_Object); |
| 3739 | extern void syms_of_xdisp (void); | 3740 | extern void syms_of_xdisp (void); |
diff --git a/src/lread.c b/src/lread.c index 72b68df6631..5d1676b0c9c 100644 --- a/src/lread.c +++ b/src/lread.c | |||
| @@ -537,6 +537,34 @@ readbyte_from_string (int c, Lisp_Object readcharfun) | |||
| 537 | } | 537 | } |
| 538 | 538 | ||
| 539 | 539 | ||
| 540 | /* Signal Qinvalid_read_syntax error. | ||
| 541 | S is error string of length N (if > 0) */ | ||
| 542 | |||
| 543 | static AVOID | ||
| 544 | invalid_syntax_lisp (Lisp_Object s, Lisp_Object readcharfun) | ||
| 545 | { | ||
| 546 | if (BUFFERP (readcharfun)) | ||
| 547 | { | ||
| 548 | xsignal1 (Qinvalid_read_syntax, | ||
| 549 | CALLN (Fformat, build_string ("%s (line %d, column %d)"), | ||
| 550 | s, | ||
| 551 | /* We should already be in the readcharfun | ||
| 552 | buffer when this error is called, so no need | ||
| 553 | to switch to it first. */ | ||
| 554 | make_fixnum (count_lines (BEGV_BYTE, PT_BYTE) + 1), | ||
| 555 | make_fixnum (current_column ()))); | ||
| 556 | } | ||
| 557 | else | ||
| 558 | xsignal1 (Qinvalid_read_syntax, s); | ||
| 559 | } | ||
| 560 | |||
| 561 | static AVOID | ||
| 562 | invalid_syntax (const char *s, Lisp_Object readcharfun) | ||
| 563 | { | ||
| 564 | invalid_syntax_lisp (build_string (s), readcharfun); | ||
| 565 | } | ||
| 566 | |||
| 567 | |||
| 540 | /* Read one non-ASCII character from INFILE. The character is | 568 | /* Read one non-ASCII character from INFILE. The character is |
| 541 | encoded in `emacs-mule' and the first byte is already read in | 569 | encoded in `emacs-mule' and the first byte is already read in |
| 542 | C. */ | 570 | C. */ |
| @@ -594,8 +622,7 @@ read_emacs_mule_char (int c, int (*readbyte) (int, Lisp_Object), Lisp_Object rea | |||
| 594 | } | 622 | } |
| 595 | c = DECODE_CHAR (charset, code); | 623 | c = DECODE_CHAR (charset, code); |
| 596 | if (c < 0) | 624 | if (c < 0) |
| 597 | Fsignal (Qinvalid_read_syntax, | 625 | invalid_syntax ("invalid multibyte form", readcharfun); |
| 598 | list1 (build_string ("invalid multibyte form"))); | ||
| 599 | return c; | 626 | return c; |
| 600 | } | 627 | } |
| 601 | 628 | ||
| @@ -2330,16 +2357,6 @@ read_internal_start (Lisp_Object stream, Lisp_Object start, Lisp_Object end) | |||
| 2330 | } | 2357 | } |
| 2331 | 2358 | ||
| 2332 | 2359 | ||
| 2333 | /* Signal Qinvalid_read_syntax error. | ||
| 2334 | S is error string of length N (if > 0) */ | ||
| 2335 | |||
| 2336 | static AVOID | ||
| 2337 | invalid_syntax (const char *s) | ||
| 2338 | { | ||
| 2339 | xsignal1 (Qinvalid_read_syntax, build_string (s)); | ||
| 2340 | } | ||
| 2341 | |||
| 2342 | |||
| 2343 | /* Use this for recursive reads, in contexts where internal tokens | 2360 | /* Use this for recursive reads, in contexts where internal tokens |
| 2344 | are not allowed. */ | 2361 | are not allowed. */ |
| 2345 | 2362 | ||
| @@ -2353,8 +2370,8 @@ read0 (Lisp_Object readcharfun) | |||
| 2353 | if (!c) | 2370 | if (!c) |
| 2354 | return val; | 2371 | return val; |
| 2355 | 2372 | ||
| 2356 | xsignal1 (Qinvalid_read_syntax, | 2373 | invalid_syntax_lisp (Fmake_string (make_fixnum (1), make_fixnum (c), Qnil), |
| 2357 | Fmake_string (make_fixnum (1), make_fixnum (c), Qnil)); | 2374 | readcharfun); |
| 2358 | } | 2375 | } |
| 2359 | 2376 | ||
| 2360 | /* Grow a read buffer BUF that contains OFFSET useful bytes of data, | 2377 | /* Grow a read buffer BUF that contains OFFSET useful bytes of data, |
| @@ -2384,7 +2401,8 @@ grow_read_buffer (char *buf, ptrdiff_t offset, | |||
| 2384 | /* Return the scalar value that has the Unicode character name NAME. | 2401 | /* Return the scalar value that has the Unicode character name NAME. |
| 2385 | Raise 'invalid-read-syntax' if there is no such character. */ | 2402 | Raise 'invalid-read-syntax' if there is no such character. */ |
| 2386 | static int | 2403 | static int |
| 2387 | character_name_to_code (char const *name, ptrdiff_t name_len) | 2404 | character_name_to_code (char const *name, ptrdiff_t name_len, |
| 2405 | Lisp_Object readcharfun) | ||
| 2388 | { | 2406 | { |
| 2389 | /* For "U+XXXX", pass the leading '+' to string_to_number to reject | 2407 | /* For "U+XXXX", pass the leading '+' to string_to_number to reject |
| 2390 | monstrosities like "U+-0000". */ | 2408 | monstrosities like "U+-0000". */ |
| @@ -2400,7 +2418,7 @@ character_name_to_code (char const *name, ptrdiff_t name_len) | |||
| 2400 | { | 2418 | { |
| 2401 | AUTO_STRING (format, "\\N{%s}"); | 2419 | AUTO_STRING (format, "\\N{%s}"); |
| 2402 | AUTO_STRING_WITH_LEN (namestr, name, name_len); | 2420 | AUTO_STRING_WITH_LEN (namestr, name, name_len); |
| 2403 | xsignal1 (Qinvalid_read_syntax, CALLN (Fformat, format, namestr)); | 2421 | invalid_syntax_lisp (CALLN (Fformat, format, namestr), readcharfun); |
| 2404 | } | 2422 | } |
| 2405 | 2423 | ||
| 2406 | return XFIXNUM (code); | 2424 | return XFIXNUM (code); |
| @@ -2619,7 +2637,7 @@ read_escape (Lisp_Object readcharfun, bool stringp) | |||
| 2619 | { | 2637 | { |
| 2620 | c = READCHAR; | 2638 | c = READCHAR; |
| 2621 | if (c != '{') | 2639 | if (c != '{') |
| 2622 | invalid_syntax ("Expected opening brace after \\N"); | 2640 | invalid_syntax ("Expected opening brace after \\N", readcharfun); |
| 2623 | char name[UNICODE_CHARACTER_NAME_LENGTH_BOUND + 1]; | 2641 | char name[UNICODE_CHARACTER_NAME_LENGTH_BOUND + 1]; |
| 2624 | bool whitespace = false; | 2642 | bool whitespace = false; |
| 2625 | ptrdiff_t length = 0; | 2643 | ptrdiff_t length = 0; |
| @@ -2634,8 +2652,9 @@ read_escape (Lisp_Object readcharfun, bool stringp) | |||
| 2634 | { | 2652 | { |
| 2635 | AUTO_STRING (format, | 2653 | AUTO_STRING (format, |
| 2636 | "Invalid character U+%04X in character name"); | 2654 | "Invalid character U+%04X in character name"); |
| 2637 | xsignal1 (Qinvalid_read_syntax, | 2655 | invalid_syntax_lisp (CALLN (Fformat, format, |
| 2638 | CALLN (Fformat, format, make_fixed_natnum (c))); | 2656 | make_fixed_natnum (c)), |
| 2657 | readcharfun); | ||
| 2639 | } | 2658 | } |
| 2640 | /* Treat multiple adjacent whitespace characters as a | 2659 | /* Treat multiple adjacent whitespace characters as a |
| 2641 | single space character. This makes it easier to use | 2660 | single space character. This makes it easier to use |
| @@ -2651,15 +2670,15 @@ read_escape (Lisp_Object readcharfun, bool stringp) | |||
| 2651 | whitespace = false; | 2670 | whitespace = false; |
| 2652 | name[length++] = c; | 2671 | name[length++] = c; |
| 2653 | if (length >= sizeof name) | 2672 | if (length >= sizeof name) |
| 2654 | invalid_syntax ("Character name too long"); | 2673 | invalid_syntax ("Character name too long", readcharfun); |
| 2655 | } | 2674 | } |
| 2656 | if (length == 0) | 2675 | if (length == 0) |
| 2657 | invalid_syntax ("Empty character name"); | 2676 | invalid_syntax ("Empty character name", readcharfun); |
| 2658 | name[length] = '\0'; | 2677 | name[length] = '\0'; |
| 2659 | 2678 | ||
| 2660 | /* character_name_to_code can invoke read1, recursively. | 2679 | /* character_name_to_code can invoke read1, recursively. |
| 2661 | This is why read1's buffer is not static. */ | 2680 | This is why read1's buffer is not static. */ |
| 2662 | return character_name_to_code (name, length); | 2681 | return character_name_to_code (name, length, readcharfun); |
| 2663 | } | 2682 | } |
| 2664 | 2683 | ||
| 2665 | default: | 2684 | default: |
| @@ -2697,10 +2716,11 @@ enum { stackbufsize = max (64, | |||
| 2697 | + INT_STRLEN_BOUND (EMACS_INT) + 1)) }; | 2716 | + INT_STRLEN_BOUND (EMACS_INT) + 1)) }; |
| 2698 | 2717 | ||
| 2699 | static void | 2718 | static void |
| 2700 | invalid_radix_integer (EMACS_INT radix, char stackbuf[VLA_ELEMS (stackbufsize)]) | 2719 | invalid_radix_integer (EMACS_INT radix, char stackbuf[VLA_ELEMS (stackbufsize)], |
| 2720 | Lisp_Object readcharfun) | ||
| 2701 | { | 2721 | { |
| 2702 | sprintf (stackbuf, invalid_radix_integer_format, radix); | 2722 | sprintf (stackbuf, invalid_radix_integer_format, radix); |
| 2703 | invalid_syntax (stackbuf); | 2723 | invalid_syntax (stackbuf, readcharfun); |
| 2704 | } | 2724 | } |
| 2705 | 2725 | ||
| 2706 | /* Read an integer in radix RADIX using READCHARFUN to read | 2726 | /* Read an integer in radix RADIX using READCHARFUN to read |
| @@ -2760,7 +2780,7 @@ read_integer (Lisp_Object readcharfun, int radix, | |||
| 2760 | UNREAD (c); | 2780 | UNREAD (c); |
| 2761 | 2781 | ||
| 2762 | if (valid != 1) | 2782 | if (valid != 1) |
| 2763 | invalid_radix_integer (radix, stackbuf); | 2783 | invalid_radix_integer (radix, stackbuf, readcharfun); |
| 2764 | 2784 | ||
| 2765 | *p = '\0'; | 2785 | *p = '\0'; |
| 2766 | return unbind_to (count, string_to_number (read_buffer, radix, NULL)); | 2786 | return unbind_to (count, string_to_number (read_buffer, radix, NULL)); |
| @@ -2896,7 +2916,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 2896 | return ht; | 2916 | return ht; |
| 2897 | } | 2917 | } |
| 2898 | UNREAD (c); | 2918 | UNREAD (c); |
| 2899 | invalid_syntax ("#"); | 2919 | invalid_syntax ("#", readcharfun); |
| 2900 | } | 2920 | } |
| 2901 | if (c == '^') | 2921 | if (c == '^') |
| 2902 | { | 2922 | { |
| @@ -2948,9 +2968,9 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 2948 | } | 2968 | } |
| 2949 | return tbl; | 2969 | return tbl; |
| 2950 | } | 2970 | } |
| 2951 | invalid_syntax ("#^^"); | 2971 | invalid_syntax ("#^^", readcharfun); |
| 2952 | } | 2972 | } |
| 2953 | invalid_syntax ("#^"); | 2973 | invalid_syntax ("#^", readcharfun); |
| 2954 | } | 2974 | } |
| 2955 | if (c == '&') | 2975 | if (c == '&') |
| 2956 | { | 2976 | { |
| @@ -2973,7 +2993,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 2973 | version. */ | 2993 | version. */ |
| 2974 | && ! (XFIXNAT (length) | 2994 | && ! (XFIXNAT (length) |
| 2975 | == (SCHARS (tmp) - 1) * BOOL_VECTOR_BITS_PER_CHAR))) | 2995 | == (SCHARS (tmp) - 1) * BOOL_VECTOR_BITS_PER_CHAR))) |
| 2976 | invalid_syntax ("#&..."); | 2996 | invalid_syntax ("#&...", readcharfun); |
| 2977 | 2997 | ||
| 2978 | val = make_uninit_bool_vector (XFIXNAT (length)); | 2998 | val = make_uninit_bool_vector (XFIXNAT (length)); |
| 2979 | data = bool_vector_uchar_data (val); | 2999 | data = bool_vector_uchar_data (val); |
| @@ -2984,7 +3004,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 2984 | &= (1 << (XFIXNUM (length) % BOOL_VECTOR_BITS_PER_CHAR)) - 1; | 3004 | &= (1 << (XFIXNUM (length) % BOOL_VECTOR_BITS_PER_CHAR)) - 1; |
| 2985 | return val; | 3005 | return val; |
| 2986 | } | 3006 | } |
| 2987 | invalid_syntax ("#&..."); | 3007 | invalid_syntax ("#&...", readcharfun); |
| 2988 | } | 3008 | } |
| 2989 | if (c == '[') | 3009 | if (c == '[') |
| 2990 | { | 3010 | { |
| @@ -3002,7 +3022,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 3002 | && VECTORP (AREF (tmp, COMPILED_CONSTANTS))) | 3022 | && VECTORP (AREF (tmp, COMPILED_CONSTANTS))) |
| 3003 | || CONSP (AREF (tmp, COMPILED_BYTECODE))) | 3023 | || CONSP (AREF (tmp, COMPILED_BYTECODE))) |
| 3004 | && FIXNATP (AREF (tmp, COMPILED_STACK_DEPTH)))) | 3024 | && FIXNATP (AREF (tmp, COMPILED_STACK_DEPTH)))) |
| 3005 | invalid_syntax ("Invalid byte-code object"); | 3025 | invalid_syntax ("Invalid byte-code object", readcharfun); |
| 3006 | 3026 | ||
| 3007 | if (STRINGP (AREF (tmp, COMPILED_BYTECODE)) | 3027 | if (STRINGP (AREF (tmp, COMPILED_BYTECODE)) |
| 3008 | && STRING_MULTIBYTE (AREF (tmp, COMPILED_BYTECODE))) | 3028 | && STRING_MULTIBYTE (AREF (tmp, COMPILED_BYTECODE))) |
| @@ -3044,7 +3064,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 3044 | /* Read the string itself. */ | 3064 | /* Read the string itself. */ |
| 3045 | tmp = read1 (readcharfun, &ch, 0); | 3065 | tmp = read1 (readcharfun, &ch, 0); |
| 3046 | if (ch != 0 || !STRINGP (tmp)) | 3066 | if (ch != 0 || !STRINGP (tmp)) |
| 3047 | invalid_syntax ("#"); | 3067 | invalid_syntax ("#", readcharfun); |
| 3048 | /* Read the intervals and their properties. */ | 3068 | /* Read the intervals and their properties. */ |
| 3049 | while (1) | 3069 | while (1) |
| 3050 | { | 3070 | { |
| @@ -3059,7 +3079,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 3059 | if (ch == 0) | 3079 | if (ch == 0) |
| 3060 | plist = read1 (readcharfun, &ch, 0); | 3080 | plist = read1 (readcharfun, &ch, 0); |
| 3061 | if (ch) | 3081 | if (ch) |
| 3062 | invalid_syntax ("Invalid string property list"); | 3082 | invalid_syntax ("Invalid string property list", readcharfun); |
| 3063 | Fset_text_properties (beg, end, plist, tmp); | 3083 | Fset_text_properties (beg, end, plist, tmp); |
| 3064 | } | 3084 | } |
| 3065 | 3085 | ||
| @@ -3207,7 +3227,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 3207 | if (c == 'r' || c == 'R') | 3227 | if (c == 'r' || c == 'R') |
| 3208 | { | 3228 | { |
| 3209 | if (! (2 <= n && n <= 36)) | 3229 | if (! (2 <= n && n <= 36)) |
| 3210 | invalid_radix_integer (n, stackbuf); | 3230 | invalid_radix_integer (n, stackbuf, readcharfun); |
| 3211 | return read_integer (readcharfun, n, stackbuf); | 3231 | return read_integer (readcharfun, n, stackbuf); |
| 3212 | } | 3232 | } |
| 3213 | 3233 | ||
| @@ -3301,7 +3321,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 3301 | return read_integer (readcharfun, 2, stackbuf); | 3321 | return read_integer (readcharfun, 2, stackbuf); |
| 3302 | 3322 | ||
| 3303 | UNREAD (c); | 3323 | UNREAD (c); |
| 3304 | invalid_syntax ("#"); | 3324 | invalid_syntax ("#", readcharfun); |
| 3305 | 3325 | ||
| 3306 | case ';': | 3326 | case ';': |
| 3307 | while ((c = READCHAR) >= 0 && c != '\n'); | 3327 | while ((c = READCHAR) >= 0 && c != '\n'); |
| @@ -3373,7 +3393,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 3373 | if (ok) | 3393 | if (ok) |
| 3374 | return make_fixnum (c); | 3394 | return make_fixnum (c); |
| 3375 | 3395 | ||
| 3376 | invalid_syntax ("?"); | 3396 | invalid_syntax ("?", readcharfun); |
| 3377 | } | 3397 | } |
| 3378 | 3398 | ||
| 3379 | case '"': | 3399 | case '"': |
| @@ -3459,7 +3479,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 3459 | 3479 | ||
| 3460 | /* Any modifiers remaining are invalid. */ | 3480 | /* Any modifiers remaining are invalid. */ |
| 3461 | if (modifiers) | 3481 | if (modifiers) |
| 3462 | invalid_syntax ("Invalid modifier in string"); | 3482 | invalid_syntax ("Invalid modifier in string", readcharfun); |
| 3463 | p += CHAR_STRING (ch, (unsigned char *) p); | 3483 | p += CHAR_STRING (ch, (unsigned char *) p); |
| 3464 | } | 3484 | } |
| 3465 | else | 3485 | else |
| @@ -3999,7 +4019,7 @@ read_list (bool flag, Lisp_Object readcharfun) | |||
| 3999 | { | 4019 | { |
| 4000 | if (ch == ']') | 4020 | if (ch == ']') |
| 4001 | return val; | 4021 | return val; |
| 4002 | invalid_syntax (") or . in a vector"); | 4022 | invalid_syntax (") or . in a vector", readcharfun); |
| 4003 | } | 4023 | } |
| 4004 | if (ch == ')') | 4024 | if (ch == ')') |
| 4005 | return val; | 4025 | return val; |
| @@ -4079,9 +4099,9 @@ read_list (bool flag, Lisp_Object readcharfun) | |||
| 4079 | 4099 | ||
| 4080 | return val; | 4100 | return val; |
| 4081 | } | 4101 | } |
| 4082 | invalid_syntax (". in wrong context"); | 4102 | invalid_syntax (". in wrong context", readcharfun); |
| 4083 | } | 4103 | } |
| 4084 | invalid_syntax ("] in a list"); | 4104 | invalid_syntax ("] in a list", readcharfun); |
| 4085 | } | 4105 | } |
| 4086 | tem = list1 (elt); | 4106 | tem = list1 (elt); |
| 4087 | if (!NILP (tail)) | 4107 | if (!NILP (tail)) |
diff --git a/src/xdisp.c b/src/xdisp.c index 32b359098aa..efca6f641fb 100644 --- a/src/xdisp.c +++ b/src/xdisp.c | |||
| @@ -26969,6 +26969,15 @@ decode_mode_spec (struct window *w, register int c, int field_width, | |||
| 26969 | return ""; | 26969 | return ""; |
| 26970 | } | 26970 | } |
| 26971 | 26971 | ||
| 26972 | /* Return the number of lines between start_byte and end_byte in the | ||
| 26973 | current buffer. */ | ||
| 26974 | |||
| 26975 | ptrdiff_t | ||
| 26976 | count_lines (ptrdiff_t start_byte, ptrdiff_t end_byte) | ||
| 26977 | { | ||
| 26978 | ptrdiff_t ignored; | ||
| 26979 | return display_count_lines (start_byte, end_byte, ZV, &ignored); | ||
| 26980 | } | ||
| 26972 | 26981 | ||
| 26973 | /* Count up to COUNT lines starting from START_BYTE. COUNT negative | 26982 | /* Count up to COUNT lines starting from START_BYTE. COUNT negative |
| 26974 | means count lines back from START_BYTE. But don't go beyond | 26983 | means count lines back from START_BYTE. But don't go beyond |