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.
This commit is contained in:
parent
3990716a97
commit
e38e7b7bc1
3 changed files with 70 additions and 40 deletions
|
@ -3734,6 +3734,7 @@ extern void message_log_maybe_newline (void);
|
|||
extern void update_echo_area (void);
|
||||
extern void truncate_echo_area (ptrdiff_t);
|
||||
extern void redisplay (void);
|
||||
extern ptrdiff_t count_lines (ptrdiff_t start_byte, ptrdiff_t end_byte);
|
||||
|
||||
void set_frame_cursor_types (struct frame *, Lisp_Object);
|
||||
extern void syms_of_xdisp (void);
|
||||
|
|
100
src/lread.c
100
src/lread.c
|
@ -537,6 +537,34 @@ readbyte_from_string (int c, Lisp_Object readcharfun)
|
|||
}
|
||||
|
||||
|
||||
/* Signal Qinvalid_read_syntax error.
|
||||
S is error string of length N (if > 0) */
|
||||
|
||||
static AVOID
|
||||
invalid_syntax_lisp (Lisp_Object s, Lisp_Object readcharfun)
|
||||
{
|
||||
if (BUFFERP (readcharfun))
|
||||
{
|
||||
xsignal1 (Qinvalid_read_syntax,
|
||||
CALLN (Fformat, build_string ("%s (line %d, column %d)"),
|
||||
s,
|
||||
/* We should already be in the readcharfun
|
||||
buffer when this error is called, so no need
|
||||
to switch to it first. */
|
||||
make_fixnum (count_lines (BEGV_BYTE, PT_BYTE) + 1),
|
||||
make_fixnum (current_column ())));
|
||||
}
|
||||
else
|
||||
xsignal1 (Qinvalid_read_syntax, s);
|
||||
}
|
||||
|
||||
static AVOID
|
||||
invalid_syntax (const char *s, Lisp_Object readcharfun)
|
||||
{
|
||||
invalid_syntax_lisp (build_string (s), readcharfun);
|
||||
}
|
||||
|
||||
|
||||
/* Read one non-ASCII character from INFILE. The character is
|
||||
encoded in `emacs-mule' and the first byte is already read in
|
||||
C. */
|
||||
|
@ -594,8 +622,7 @@ read_emacs_mule_char (int c, int (*readbyte) (int, Lisp_Object), Lisp_Object rea
|
|||
}
|
||||
c = DECODE_CHAR (charset, code);
|
||||
if (c < 0)
|
||||
Fsignal (Qinvalid_read_syntax,
|
||||
list1 (build_string ("invalid multibyte form")));
|
||||
invalid_syntax ("invalid multibyte form", readcharfun);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
@ -2330,16 +2357,6 @@ read_internal_start (Lisp_Object stream, Lisp_Object start, Lisp_Object end)
|
|||
}
|
||||
|
||||
|
||||
/* Signal Qinvalid_read_syntax error.
|
||||
S is error string of length N (if > 0) */
|
||||
|
||||
static AVOID
|
||||
invalid_syntax (const char *s)
|
||||
{
|
||||
xsignal1 (Qinvalid_read_syntax, build_string (s));
|
||||
}
|
||||
|
||||
|
||||
/* Use this for recursive reads, in contexts where internal tokens
|
||||
are not allowed. */
|
||||
|
||||
|
@ -2353,8 +2370,8 @@ read0 (Lisp_Object readcharfun)
|
|||
if (!c)
|
||||
return val;
|
||||
|
||||
xsignal1 (Qinvalid_read_syntax,
|
||||
Fmake_string (make_fixnum (1), make_fixnum (c), Qnil));
|
||||
invalid_syntax_lisp (Fmake_string (make_fixnum (1), make_fixnum (c), Qnil),
|
||||
readcharfun);
|
||||
}
|
||||
|
||||
/* Grow a read buffer BUF that contains OFFSET useful bytes of data,
|
||||
|
@ -2384,7 +2401,8 @@ grow_read_buffer (char *buf, ptrdiff_t offset,
|
|||
/* Return the scalar value that has the Unicode character name NAME.
|
||||
Raise 'invalid-read-syntax' if there is no such character. */
|
||||
static int
|
||||
character_name_to_code (char const *name, ptrdiff_t name_len)
|
||||
character_name_to_code (char const *name, ptrdiff_t name_len,
|
||||
Lisp_Object readcharfun)
|
||||
{
|
||||
/* For "U+XXXX", pass the leading '+' to string_to_number to reject
|
||||
monstrosities like "U+-0000". */
|
||||
|
@ -2400,7 +2418,7 @@ character_name_to_code (char const *name, ptrdiff_t name_len)
|
|||
{
|
||||
AUTO_STRING (format, "\\N{%s}");
|
||||
AUTO_STRING_WITH_LEN (namestr, name, name_len);
|
||||
xsignal1 (Qinvalid_read_syntax, CALLN (Fformat, format, namestr));
|
||||
invalid_syntax_lisp (CALLN (Fformat, format, namestr), readcharfun);
|
||||
}
|
||||
|
||||
return XFIXNUM (code);
|
||||
|
@ -2619,7 +2637,7 @@ read_escape (Lisp_Object readcharfun, bool stringp)
|
|||
{
|
||||
c = READCHAR;
|
||||
if (c != '{')
|
||||
invalid_syntax ("Expected opening brace after \\N");
|
||||
invalid_syntax ("Expected opening brace after \\N", readcharfun);
|
||||
char name[UNICODE_CHARACTER_NAME_LENGTH_BOUND + 1];
|
||||
bool whitespace = false;
|
||||
ptrdiff_t length = 0;
|
||||
|
@ -2634,8 +2652,9 @@ read_escape (Lisp_Object readcharfun, bool stringp)
|
|||
{
|
||||
AUTO_STRING (format,
|
||||
"Invalid character U+%04X in character name");
|
||||
xsignal1 (Qinvalid_read_syntax,
|
||||
CALLN (Fformat, format, make_fixed_natnum (c)));
|
||||
invalid_syntax_lisp (CALLN (Fformat, format,
|
||||
make_fixed_natnum (c)),
|
||||
readcharfun);
|
||||
}
|
||||
/* Treat multiple adjacent whitespace characters as a
|
||||
single space character. This makes it easier to use
|
||||
|
@ -2651,15 +2670,15 @@ read_escape (Lisp_Object readcharfun, bool stringp)
|
|||
whitespace = false;
|
||||
name[length++] = c;
|
||||
if (length >= sizeof name)
|
||||
invalid_syntax ("Character name too long");
|
||||
invalid_syntax ("Character name too long", readcharfun);
|
||||
}
|
||||
if (length == 0)
|
||||
invalid_syntax ("Empty character name");
|
||||
invalid_syntax ("Empty character name", readcharfun);
|
||||
name[length] = '\0';
|
||||
|
||||
/* character_name_to_code can invoke read1, recursively.
|
||||
This is why read1's buffer is not static. */
|
||||
return character_name_to_code (name, length);
|
||||
return character_name_to_code (name, length, readcharfun);
|
||||
}
|
||||
|
||||
default:
|
||||
|
@ -2697,10 +2716,11 @@ enum { stackbufsize = max (64,
|
|||
+ INT_STRLEN_BOUND (EMACS_INT) + 1)) };
|
||||
|
||||
static void
|
||||
invalid_radix_integer (EMACS_INT radix, char stackbuf[VLA_ELEMS (stackbufsize)])
|
||||
invalid_radix_integer (EMACS_INT radix, char stackbuf[VLA_ELEMS (stackbufsize)],
|
||||
Lisp_Object readcharfun)
|
||||
{
|
||||
sprintf (stackbuf, invalid_radix_integer_format, radix);
|
||||
invalid_syntax (stackbuf);
|
||||
invalid_syntax (stackbuf, readcharfun);
|
||||
}
|
||||
|
||||
/* Read an integer in radix RADIX using READCHARFUN to read
|
||||
|
@ -2760,7 +2780,7 @@ read_integer (Lisp_Object readcharfun, int radix,
|
|||
UNREAD (c);
|
||||
|
||||
if (valid != 1)
|
||||
invalid_radix_integer (radix, stackbuf);
|
||||
invalid_radix_integer (radix, stackbuf, readcharfun);
|
||||
|
||||
*p = '\0';
|
||||
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)
|
|||
return ht;
|
||||
}
|
||||
UNREAD (c);
|
||||
invalid_syntax ("#");
|
||||
invalid_syntax ("#", readcharfun);
|
||||
}
|
||||
if (c == '^')
|
||||
{
|
||||
|
@ -2948,9 +2968,9 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
|
|||
}
|
||||
return tbl;
|
||||
}
|
||||
invalid_syntax ("#^^");
|
||||
invalid_syntax ("#^^", readcharfun);
|
||||
}
|
||||
invalid_syntax ("#^");
|
||||
invalid_syntax ("#^", readcharfun);
|
||||
}
|
||||
if (c == '&')
|
||||
{
|
||||
|
@ -2973,7 +2993,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
|
|||
version. */
|
||||
&& ! (XFIXNAT (length)
|
||||
== (SCHARS (tmp) - 1) * BOOL_VECTOR_BITS_PER_CHAR)))
|
||||
invalid_syntax ("#&...");
|
||||
invalid_syntax ("#&...", readcharfun);
|
||||
|
||||
val = make_uninit_bool_vector (XFIXNAT (length));
|
||||
data = bool_vector_uchar_data (val);
|
||||
|
@ -2984,7 +3004,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
|
|||
&= (1 << (XFIXNUM (length) % BOOL_VECTOR_BITS_PER_CHAR)) - 1;
|
||||
return val;
|
||||
}
|
||||
invalid_syntax ("#&...");
|
||||
invalid_syntax ("#&...", readcharfun);
|
||||
}
|
||||
if (c == '[')
|
||||
{
|
||||
|
@ -3002,7 +3022,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
|
|||
&& VECTORP (AREF (tmp, COMPILED_CONSTANTS)))
|
||||
|| CONSP (AREF (tmp, COMPILED_BYTECODE)))
|
||||
&& FIXNATP (AREF (tmp, COMPILED_STACK_DEPTH))))
|
||||
invalid_syntax ("Invalid byte-code object");
|
||||
invalid_syntax ("Invalid byte-code object", readcharfun);
|
||||
|
||||
if (STRINGP (AREF (tmp, COMPILED_BYTECODE))
|
||||
&& STRING_MULTIBYTE (AREF (tmp, COMPILED_BYTECODE)))
|
||||
|
@ -3044,7 +3064,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
|
|||
/* Read the string itself. */
|
||||
tmp = read1 (readcharfun, &ch, 0);
|
||||
if (ch != 0 || !STRINGP (tmp))
|
||||
invalid_syntax ("#");
|
||||
invalid_syntax ("#", readcharfun);
|
||||
/* Read the intervals and their properties. */
|
||||
while (1)
|
||||
{
|
||||
|
@ -3059,7 +3079,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
|
|||
if (ch == 0)
|
||||
plist = read1 (readcharfun, &ch, 0);
|
||||
if (ch)
|
||||
invalid_syntax ("Invalid string property list");
|
||||
invalid_syntax ("Invalid string property list", readcharfun);
|
||||
Fset_text_properties (beg, end, plist, tmp);
|
||||
}
|
||||
|
||||
|
@ -3207,7 +3227,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
|
|||
if (c == 'r' || c == 'R')
|
||||
{
|
||||
if (! (2 <= n && n <= 36))
|
||||
invalid_radix_integer (n, stackbuf);
|
||||
invalid_radix_integer (n, stackbuf, readcharfun);
|
||||
return read_integer (readcharfun, n, stackbuf);
|
||||
}
|
||||
|
||||
|
@ -3301,7 +3321,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
|
|||
return read_integer (readcharfun, 2, stackbuf);
|
||||
|
||||
UNREAD (c);
|
||||
invalid_syntax ("#");
|
||||
invalid_syntax ("#", readcharfun);
|
||||
|
||||
case ';':
|
||||
while ((c = READCHAR) >= 0 && c != '\n');
|
||||
|
@ -3373,7 +3393,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
|
|||
if (ok)
|
||||
return make_fixnum (c);
|
||||
|
||||
invalid_syntax ("?");
|
||||
invalid_syntax ("?", readcharfun);
|
||||
}
|
||||
|
||||
case '"':
|
||||
|
@ -3459,7 +3479,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
|
|||
|
||||
/* Any modifiers remaining are invalid. */
|
||||
if (modifiers)
|
||||
invalid_syntax ("Invalid modifier in string");
|
||||
invalid_syntax ("Invalid modifier in string", readcharfun);
|
||||
p += CHAR_STRING (ch, (unsigned char *) p);
|
||||
}
|
||||
else
|
||||
|
@ -3999,7 +4019,7 @@ read_list (bool flag, Lisp_Object readcharfun)
|
|||
{
|
||||
if (ch == ']')
|
||||
return val;
|
||||
invalid_syntax (") or . in a vector");
|
||||
invalid_syntax (") or . in a vector", readcharfun);
|
||||
}
|
||||
if (ch == ')')
|
||||
return val;
|
||||
|
@ -4079,9 +4099,9 @@ read_list (bool flag, Lisp_Object readcharfun)
|
|||
|
||||
return val;
|
||||
}
|
||||
invalid_syntax (". in wrong context");
|
||||
invalid_syntax (". in wrong context", readcharfun);
|
||||
}
|
||||
invalid_syntax ("] in a list");
|
||||
invalid_syntax ("] in a list", readcharfun);
|
||||
}
|
||||
tem = list1 (elt);
|
||||
if (!NILP (tail))
|
||||
|
|
|
@ -26969,6 +26969,15 @@ decode_mode_spec (struct window *w, register int c, int field_width,
|
|||
return "";
|
||||
}
|
||||
|
||||
/* Return the number of lines between start_byte and end_byte in the
|
||||
current buffer. */
|
||||
|
||||
ptrdiff_t
|
||||
count_lines (ptrdiff_t start_byte, ptrdiff_t end_byte)
|
||||
{
|
||||
ptrdiff_t ignored;
|
||||
return display_count_lines (start_byte, end_byte, ZV, &ignored);
|
||||
}
|
||||
|
||||
/* Count up to COUNT lines starting from START_BYTE. COUNT negative
|
||||
means count lines back from START_BYTE. But don't go beyond
|
||||
|
|
Loading…
Add table
Reference in a new issue