summaryrefslogtreecommitdiff
path: root/Parser
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2018-12-17 17:34:14 +0200
committerGitHub <noreply@github.com>2018-12-17 17:34:14 +0200
commit94cf308ee231bfbfaa9ddc50b9764545a1318773 (patch)
treeadc068a6567b6712226436ad399951ad888cb53c /Parser
parentbdabb0737c631835b246c9823852d20331243315 (diff)
downloadcpython-git-94cf308ee231bfbfaa9ddc50b9764545a1318773.tar.gz
bpo-33306: Improve SyntaxError messages for unbalanced parentheses. (GH-6516)
Diffstat (limited to 'Parser')
-rw-r--r--Parser/tokenizer.c32
-rw-r--r--Parser/tokenizer.h5
2 files changed, 36 insertions, 1 deletions
diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c
index d319a4c90a..c246ee204c 100644
--- a/Parser/tokenizer.c
+++ b/Parser/tokenizer.c
@@ -1842,12 +1842,44 @@ tok_get(struct tok_state *tok, char **p_start, char **p_end)
case '(':
case '[':
case '{':
+#ifndef PGEN
+ if (tok->level >= MAXLEVEL) {
+ return syntaxerror(tok, "too many nested parentheses");
+ }
+ tok->parenstack[tok->level] = c;
+ tok->parenlinenostack[tok->level] = tok->lineno;
+#endif
tok->level++;
break;
case ')':
case ']':
case '}':
+#ifndef PGEN
+ if (!tok->level) {
+ return syntaxerror(tok, "unmatched '%c'", c);
+ }
+#endif
tok->level--;
+#ifndef PGEN
+ int opening = tok->parenstack[tok->level];
+ if (!((opening == '(' && c == ')') ||
+ (opening == '[' && c == ']') ||
+ (opening == '{' && c == '}')))
+ {
+ if (tok->parenlinenostack[tok->level] != tok->lineno) {
+ return syntaxerror(tok,
+ "closing parenthesis '%c' does not match "
+ "opening parenthesis '%c' on line %d",
+ c, opening, tok->parenlinenostack[tok->level]);
+ }
+ else {
+ return syntaxerror(tok,
+ "closing parenthesis '%c' does not match "
+ "opening parenthesis '%c'",
+ c, opening);
+ }
+ }
+#endif
break;
}
diff --git a/Parser/tokenizer.h b/Parser/tokenizer.h
index 2e31d8624d..cd18d25dc1 100644
--- a/Parser/tokenizer.h
+++ b/Parser/tokenizer.h
@@ -11,6 +11,7 @@ extern "C" {
#include "token.h" /* For token types */
#define MAXINDENT 100 /* Max indentation level */
+#define MAXLEVEL 200 /* Max parentheses level */
enum decoding_state {
STATE_INIT,
@@ -39,14 +40,16 @@ struct tok_state {
int lineno; /* Current line number */
int level; /* () [] {} Parentheses nesting level */
/* Used to allow free continuations inside them */
- /* Stuff for checking on different tab sizes */
#ifndef PGEN
+ char parenstack[MAXLEVEL];
+ int parenlinenostack[MAXLEVEL];
/* pgen doesn't have access to Python codecs, it cannot decode the input
filename. The bytes filename might be kept, but it is only used by
indenterror() and it is not really needed: pgen only compiles one file
(Grammar/Grammar). */
PyObject *filename;
#endif
+ /* Stuff for checking on different tab sizes */
int altindstack[MAXINDENT]; /* Stack of alternate indents */
/* Stuff for PEP 0263 */
enum decoding_state decoding_state;