Skip to content

Commit abea73b

Browse files
asottilemiss-islington
authored andcommitted
bpo-2180: Treat line continuation at EOF as a SyntaxError (GH-13401)
This makes the parser consistent with the tokenize module (already the case in `pypy`). sample ------ ```python x = 5\ ``` before ------ ```console $ python3 t.py $ python3 -mtokenize t.py t.py:2:0: error: EOF in multi-line statement ``` after ----- ```console $ ./python t.py File "t.py", line 3 x = 5\ ^ SyntaxError: unexpected EOF while parsing $ ./python -m tokenize t.py t.py:2:0: error: EOF in multi-line statement ``` https://bugs.python.org/issue2180
1 parent e917f2e commit abea73b

File tree

3 files changed

+36
-2
lines changed

3 files changed

+36
-2
lines changed

Lib/test/test_eof.py

+25-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
"""test script for a few new invalid token catches"""
22

3-
import unittest
3+
import sys
44
from test import support
5+
from test.support import script_helper
6+
import unittest
57

68
class EOFTestCase(unittest.TestCase):
79
def test_EOFC(self):
@@ -24,5 +26,27 @@ def test_EOFS(self):
2426
else:
2527
raise support.TestFailed
2628

29+
def test_line_continuation_EOF(self):
30+
"""A contination at the end of input must be an error; bpo2180."""
31+
expect = 'unexpected EOF while parsing (<string>, line 1)'
32+
with self.assertRaises(SyntaxError) as excinfo:
33+
exec('x = 5\\')
34+
self.assertEqual(str(excinfo.exception), expect)
35+
with self.assertRaises(SyntaxError) as excinfo:
36+
exec('\\')
37+
self.assertEqual(str(excinfo.exception), expect)
38+
39+
@unittest.skipIf(not sys.executable, "sys.executable required")
40+
def test_line_continuation_EOF_from_file_bpo2180(self):
41+
"""Ensure tok_nextc() does not add too many ending newlines."""
42+
with support.temp_dir() as temp_dir:
43+
file_name = script_helper.make_script(temp_dir, 'foo', '\\')
44+
rc, out, err = script_helper.assert_python_failure(file_name)
45+
self.assertIn(b'unexpected EOF while parsing', err)
46+
47+
file_name = script_helper.make_script(temp_dir, 'foo', 'y = 6\\')
48+
rc, out, err = script_helper.assert_python_failure(file_name)
49+
self.assertIn(b'unexpected EOF while parsing', err)
50+
2751
if __name__ == "__main__":
2852
unittest.main()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Treat line continuation at EOF as a ``SyntaxError`` by Anthony Sottile.

Parser/tokenizer.c

+10-1
Original file line numberDiff line numberDiff line change
@@ -983,7 +983,8 @@ tok_nextc(struct tok_state *tok)
983983
return EOF;
984984
/* Last line does not end in \n,
985985
fake one */
986-
strcpy(tok->inp, "\n");
986+
if (tok->inp[-1] != '\n')
987+
strcpy(tok->inp, "\n");
987988
}
988989
tok->inp = strchr(tok->inp, '\0');
989990
done = tok->inp[-1] == '\n';
@@ -1674,6 +1675,14 @@ tok_get(struct tok_state *tok, char **p_start, char **p_end)
16741675
tok->cur = tok->inp;
16751676
return ERRORTOKEN;
16761677
}
1678+
c = tok_nextc(tok);
1679+
if (c == EOF) {
1680+
tok->done = E_EOF;
1681+
tok->cur = tok->inp;
1682+
return ERRORTOKEN;
1683+
} else {
1684+
tok_backup(tok, c);
1685+
}
16771686
tok->cont_line = 1;
16781687
goto again; /* Read next line */
16791688
}

0 commit comments

Comments
 (0)