bpo-33305: Improve SyntaxError for invalid numerical literals. (GH-6517)

This commit is contained in:
Serhiy Storchaka 2018-07-09 15:09:35 +03:00 committed by GitHub
parent 2a9b8babf0
commit cf7303ed2a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 77 additions and 13 deletions

View File

@ -100,6 +100,8 @@ INVALID_UNDERSCORE_LITERALS = [
class TokenTests(unittest.TestCase): class TokenTests(unittest.TestCase):
check_syntax_error = check_syntax_error
def test_backslash(self): def test_backslash(self):
# Backslash means line continuation: # Backslash means line continuation:
x = 1 \ x = 1 \
@ -184,6 +186,28 @@ class TokenTests(unittest.TestCase):
# Sanity check: no literal begins with an underscore # Sanity check: no literal begins with an underscore
self.assertRaises(NameError, eval, "_0") self.assertRaises(NameError, eval, "_0")
def test_bad_numerical_literals(self):
check = self.check_syntax_error
check("0b12", "invalid digit '2' in binary literal")
check("0b1_2", "invalid digit '2' in binary literal")
check("0b2", "invalid digit '2' in binary literal")
check("0b1_", "invalid binary literal")
check("0b", "invalid binary literal")
check("0o18", "invalid digit '8' in octal literal")
check("0o1_8", "invalid digit '8' in octal literal")
check("0o8", "invalid digit '8' in octal literal")
check("0o1_", "invalid octal literal")
check("0o", "invalid octal literal")
check("0x1_", "invalid hexadecimal literal")
check("0x", "invalid hexadecimal literal")
check("1_", "invalid decimal literal")
check("012",
"leading zeros in decimal integer literals are not permitted; "
"use an 0o prefix for octal integers")
check("1.2_", "invalid decimal literal")
check("1e2_", "invalid decimal literal")
check("1e+", "invalid decimal literal")
def test_string_literals(self): def test_string_literals(self):
x = ''; y = ""; self.assertTrue(len(x) == 0 and x == y) x = ''; y = ""; self.assertTrue(len(x) == 0 and x == y)
x = '\''; y = "'"; self.assertTrue(len(x) == 1 and x == y and ord(x) == 39) x = '\''; y = "'"; self.assertTrue(len(x) == 1 and x == y and ord(x) == 39)

View File

@ -0,0 +1 @@
Improved syntax error messages for invalid numerical literals.

View File

@ -1280,6 +1280,28 @@ PyToken_ThreeChars(int c1, int c2, int c3)
return OP; return OP;
} }
static int
syntaxerror(struct tok_state *tok, const char *format, ...)
{
#ifndef PGEN
va_list vargs;
#ifdef HAVE_STDARG_PROTOTYPES
va_start(vargs, format);
#else
va_start(vargs);
#endif
PyErr_FormatV(PyExc_SyntaxError, format, vargs);
va_end(vargs);
PyErr_SyntaxLocationObject(tok->filename,
tok->lineno,
tok->cur - tok->line_start);
tok->done = E_ERROR;
#else
tok->done = E_TOKEN;
#endif
return ERRORTOKEN;
}
static int static int
indenterror(struct tok_state *tok) indenterror(struct tok_state *tok)
{ {
@ -1333,8 +1355,8 @@ tok_decimal_tail(struct tok_state *tok)
} }
c = tok_nextc(tok); c = tok_nextc(tok);
if (!isdigit(c)) { if (!isdigit(c)) {
tok->done = E_TOKEN;
tok_backup(tok, c); tok_backup(tok, c);
syntaxerror(tok, "invalid decimal literal");
return 0; return 0;
} }
} }
@ -1562,9 +1584,8 @@ tok_get(struct tok_state *tok, char **p_start, char **p_end)
c = tok_nextc(tok); c = tok_nextc(tok);
} }
if (!isxdigit(c)) { if (!isxdigit(c)) {
tok->done = E_TOKEN;
tok_backup(tok, c); tok_backup(tok, c);
return ERRORTOKEN; return syntaxerror(tok, "invalid hexadecimal literal");
} }
do { do {
c = tok_nextc(tok); c = tok_nextc(tok);
@ -1579,14 +1600,23 @@ tok_get(struct tok_state *tok, char **p_start, char **p_end)
c = tok_nextc(tok); c = tok_nextc(tok);
} }
if (c < '0' || c >= '8') { if (c < '0' || c >= '8') {
tok->done = E_TOKEN;
tok_backup(tok, c); tok_backup(tok, c);
return ERRORTOKEN; if (isdigit(c)) {
return syntaxerror(tok,
"invalid digit '%c' in octal literal", c);
}
else {
return syntaxerror(tok, "invalid octal literal");
}
} }
do { do {
c = tok_nextc(tok); c = tok_nextc(tok);
} while ('0' <= c && c < '8'); } while ('0' <= c && c < '8');
} while (c == '_'); } while (c == '_');
if (isdigit(c)) {
return syntaxerror(tok,
"invalid digit '%c' in octal literal", c);
}
} }
else if (c == 'b' || c == 'B') { else if (c == 'b' || c == 'B') {
/* Binary */ /* Binary */
@ -1596,14 +1626,23 @@ tok_get(struct tok_state *tok, char **p_start, char **p_end)
c = tok_nextc(tok); c = tok_nextc(tok);
} }
if (c != '0' && c != '1') { if (c != '0' && c != '1') {
tok->done = E_TOKEN;
tok_backup(tok, c); tok_backup(tok, c);
return ERRORTOKEN; if (isdigit(c)) {
return syntaxerror(tok,
"invalid digit '%c' in binary literal", c);
}
else {
return syntaxerror(tok, "invalid binary literal");
}
} }
do { do {
c = tok_nextc(tok); c = tok_nextc(tok);
} while (c == '0' || c == '1'); } while (c == '0' || c == '1');
} while (c == '_'); } while (c == '_');
if (isdigit(c)) {
return syntaxerror(tok,
"invalid digit '%c' in binary literal", c);
}
} }
else { else {
int nonzero = 0; int nonzero = 0;
@ -1613,9 +1652,8 @@ tok_get(struct tok_state *tok, char **p_start, char **p_end)
if (c == '_') { if (c == '_') {
c = tok_nextc(tok); c = tok_nextc(tok);
if (!isdigit(c)) { if (!isdigit(c)) {
tok->done = E_TOKEN;
tok_backup(tok, c); tok_backup(tok, c);
return ERRORTOKEN; return syntaxerror(tok, "invalid decimal literal");
} }
} }
if (c != '0') { if (c != '0') {
@ -1642,9 +1680,11 @@ tok_get(struct tok_state *tok, char **p_start, char **p_end)
} }
else if (nonzero) { else if (nonzero) {
/* Old-style octal: now disallowed. */ /* Old-style octal: now disallowed. */
tok->done = E_TOKEN;
tok_backup(tok, c); tok_backup(tok, c);
return ERRORTOKEN; return syntaxerror(tok,
"leading zeros in decimal integer "
"literals are not permitted; "
"use an 0o prefix for octal integers");
} }
} }
} }
@ -1676,9 +1716,8 @@ tok_get(struct tok_state *tok, char **p_start, char **p_end)
if (c == '+' || c == '-') { if (c == '+' || c == '-') {
c = tok_nextc(tok); c = tok_nextc(tok);
if (!isdigit(c)) { if (!isdigit(c)) {
tok->done = E_TOKEN;
tok_backup(tok, c); tok_backup(tok, c);
return ERRORTOKEN; return syntaxerror(tok, "invalid decimal literal");
} }
} else if (!isdigit(c)) { } else if (!isdigit(c)) {
tok_backup(tok, c); tok_backup(tok, c);