diff --git a/Parser/pegen/pegen.c b/Parser/pegen/pegen.c index c80f08668b07d6..5745918bf4c182 100644 --- a/Parser/pegen/pegen.c +++ b/Parser/pegen/pegen.c @@ -780,6 +780,26 @@ _PyPegen_expect_token(Parser *p, int type) } Token *t = p->tokens[p->mark]; if (t->type != type) { + int current = p->mark; + if (current >= p->last_err_line) { + if (current > p->last_err_line) { + Py_DECREF(p->err_tokens); + p->err_tokens = PySet_New(0); + p->last_err_line= current; + } + if (PyBytes_AS_STRING(t->bytes)[0] != '\0') { + for (int i=0; i < p->n_keyword_lists; i++) { + if (p->keywords[i] == NULL) { + continue; + } + for (KeywordToken *k = p->keywords[i]; k->type != -1; k++) { + if (k->type == type) { + PySet_Add(p->err_tokens, PyUnicode_FromString(k->str)); + } + } + } + } + } return NULL; } p->mark += 1; @@ -979,6 +999,7 @@ void _PyPegen_Parser_Free(Parser *p) { Py_XDECREF(p->normalize); + Py_XDECREF(p->err_tokens); for (int i = 0; i < p->size; i++) { PyMem_Free(p->tokens[i]); } @@ -1054,6 +1075,8 @@ _PyPegen_Parser_New(struct tok_state *tok, int start_rule, int flags, p->parsing_started = 0; p->normalize = NULL; p->error_indicator = 0; + p->last_err_line = 0; + p->err_tokens = PySet_New(0); p->starting_lineno = 0; p->starting_col_offset = 0; @@ -1086,7 +1109,22 @@ _PyPegen_run_parser(Parser *p) RAISE_INDENTATION_ERROR("unexpected unindent"); } else { - RAISE_SYNTAX_ERROR("invalid syntax"); + if (PySet_Size(p->err_tokens)) { + PyObject* comma = PyUnicode_FromString(", "); + if (comma == NULL) { + return NULL; + } + PyObject* error_names = PyUnicode_Join(comma, p->err_tokens); + Py_DECREF(comma); + if (error_names == NULL) { + return NULL; + } + RAISE_SYNTAX_ERROR("Invalid syntax. Expected one of: %U", error_names); + Py_DECREF(error_names); + } + else { + RAISE_SYNTAX_ERROR("Invalid syntax"); + } } } return NULL; diff --git a/Parser/pegen/pegen.h b/Parser/pegen/pegen.h index b55a652ac8060d..330ddce0da6372 100644 --- a/Parser/pegen/pegen.h +++ b/Parser/pegen/pegen.h @@ -72,6 +72,8 @@ typedef struct { int feature_version; growable_comment_array type_ignore_comments; Token *known_err_token; + int last_err_line; + PyObject* err_tokens; } Parser; typedef struct {