diff --git a/Include/errcode.h b/Include/errcode.h index 6bb3cc1e5f7..5946686c659 100644 --- a/Include/errcode.h +++ b/Include/errcode.h @@ -30,6 +30,7 @@ extern "C" { #define E_EOLS 24 /* EOL in single-quoted string */ #define E_LINECONT 25 /* Unexpected characters after a line continuation */ #define E_IDENTIFIER 26 /* Invalid characters in identifier */ +#define E_BADSINGLE 27 /* Ill-formed single statement input */ #ifdef __cplusplus } diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index c5f9189fcc0..7089872ee24 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -6,6 +6,12 @@ class TestSpecifics(unittest.TestCase): + def compile_single(self, source): + compile(source, "", "single") + + def assertInvalidSingle(self, source): + self.assertRaises(SyntaxError, self.compile_single, source) + def test_no_ending_newline(self): compile("hi", "", "exec") compile("hi\r", "", "exec") @@ -442,6 +448,28 @@ def test_same_filename_used(self): if isinstance(obj, types.CodeType): self.assertIs(obj.co_filename, c.co_filename) + def test_single_statement(self): + self.compile_single("1 + 2") + self.compile_single("\n1 + 2") + self.compile_single("1 + 2\n") + self.compile_single("1 + 2\n\n") + self.compile_single("1 + 2\t\t\n") + self.compile_single("1 + 2\t\t\n ") + self.compile_single("1 + 2 # one plus two") + self.compile_single("1; 2") + self.compile_single("import sys; sys") + self.compile_single("def f():\n pass") + self.compile_single("while False:\n pass") + self.compile_single("if x:\n f(x)") + self.compile_single("if x:\n f(x)\nelse:\n g(x)") + self.compile_single("class T:\n pass") + + def test_bad_single_statement(self): + self.assertInvalidSingle('1\n2') + self.assertInvalidSingle('def f(): pass') + self.assertInvalidSingle('a = 13\nb = 187') + self.assertInvalidSingle('del x\ndel y') + self.assertInvalidSingle('f()\ng()') def test_main(): support.run_unittest(TestSpecifics) diff --git a/Misc/NEWS b/Misc/NEWS index d7daba433ca..22244a8e76c 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ What's New in Python 3.3 Alpha 1? Core and Builtins ----------------- +- Issue #12705: A SyntaxError exception is now raised when attempting to + compile multiple statements as a single interactive statement. + - Fix the builtin module initialization code to store the init function for future reinitialization. diff --git a/Parser/parsetok.c b/Parser/parsetok.c index f22ac67254c..9b2d7306ff6 100644 --- a/Parser/parsetok.c +++ b/Parser/parsetok.c @@ -224,6 +224,23 @@ parsetok(struct tok_state *tok, grammar *g, int start, perrdetail *err_ret, if (err_ret->error == E_DONE) { n = ps->p_tree; ps->p_tree = NULL; + + /* Check that the source for a single input statement really + is a single statement by looking at what is left in the + buffer after parsing. Trailing whitespace and comments + are OK. */ + if (start == single_input) { + char *cur = tok->cur; + char c = *tok->cur; + + while (c == ' ' || c == '\t' || c == '\n' || c == '\014') + c = *++cur; + + if (c && c != '#') { + err_ret->error = E_BADSINGLE; + n = NULL; + } + } } else n = NULL; diff --git a/Python/pythonrun.c b/Python/pythonrun.c index bff04de5993..44b817f5468 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -2129,6 +2129,9 @@ err_input(perrdetail *err) case E_IDENTIFIER: msg = "invalid character in identifier"; break; + case E_BADSINGLE: + msg = "multiple statements found while compiling a single statement"; + break; default: fprintf(stderr, "error=%d\n", err->error); msg = "unknown parsing error";