diff --git a/Grammar/python.gram b/Grammar/python.gram index de2d9c7508fa0e..c02dfed59a3149 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -94,12 +94,18 @@ func_type[mod_ty]: '(' a=[type_expressions] ')' '->' b=expression NEWLINE* ENDMA # GENERAL STATEMENTS # ================== -statements[asdl_stmt_seq*]: a=statement+ { (asdl_stmt_seq*)_PyPegen_seq_flatten(p, a) } +statements[asdl_stmt_seq*]: a=statement+ { _PyPegen_register_stmts(p, (asdl_stmt_seq*)_PyPegen_seq_flatten(p, a)) } -statement[asdl_stmt_seq*]: a=compound_stmt { (asdl_stmt_seq*)_PyPegen_singleton_seq(p, a) } | a[asdl_stmt_seq*]=simple_stmts { a } +statement[asdl_stmt_seq*]: + | a=compound_stmt { (asdl_stmt_seq*)_PyPegen_singleton_seq(p, a) } + | a[asdl_stmt_seq*]=simple_stmts { a } + +single_compound_stmt[asdl_stmt_seq*]: + | a=compound_stmt { + _PyPegen_register_stmts(p, (asdl_stmt_seq*)_PyPegen_singleton_seq(p, a)) } statement_newline[asdl_stmt_seq*]: - | a=compound_stmt NEWLINE { (asdl_stmt_seq*)_PyPegen_singleton_seq(p, a) } + | a=single_compound_stmt NEWLINE { a } | simple_stmts | NEWLINE { (asdl_stmt_seq*)_PyPegen_singleton_seq(p, CHECK(stmt_ty, _PyAST_Pass(EXTRA))) } | ENDMARKER { _PyPegen_interactive_exit(p) } diff --git a/Include/cpython/pyerrors.h b/Include/cpython/pyerrors.h index b36b4681f5dddb..6b63d304b0d929 100644 --- a/Include/cpython/pyerrors.h +++ b/Include/cpython/pyerrors.h @@ -30,6 +30,7 @@ typedef struct { PyObject *end_offset; PyObject *text; PyObject *print_file_and_line; + PyObject *metadata; } PySyntaxErrorObject; typedef struct { diff --git a/Lib/codeop.py b/Lib/codeop.py index adf000ba29f88c..8cac00442d99e3 100644 --- a/Lib/codeop.py +++ b/Lib/codeop.py @@ -47,7 +47,7 @@ PyCF_ONLY_AST = 0x400 PyCF_ALLOW_INCOMPLETE_INPUT = 0x4000 -def _maybe_compile(compiler, source, filename, symbol): +def _maybe_compile(compiler, source, filename, symbol, flags): # Check for source consisting of only blank lines and comments. for line in source.split("\n"): line = line.strip() @@ -61,10 +61,10 @@ def _maybe_compile(compiler, source, filename, symbol): with warnings.catch_warnings(): warnings.simplefilter("ignore", (SyntaxWarning, DeprecationWarning)) try: - compiler(source, filename, symbol) + compiler(source, filename, symbol, flags=flags) except SyntaxError: # Let other compile() errors propagate. try: - compiler(source + "\n", filename, symbol) + compiler(source + "\n", filename, symbol, flags=flags) return None except _IncompleteInputError as e: return None @@ -74,14 +74,13 @@ def _maybe_compile(compiler, source, filename, symbol): return compiler(source, filename, symbol, incomplete_input=False) -def _compile(source, filename, symbol, incomplete_input=True): - flags = 0 +def _compile(source, filename, symbol, incomplete_input=True, *, flags=0): if incomplete_input: flags |= PyCF_ALLOW_INCOMPLETE_INPUT flags |= PyCF_DONT_IMPLY_DEDENT return compile(source, filename, symbol, flags) -def compile_command(source, filename="", symbol="single"): +def compile_command(source, filename="", symbol="single", flags=0): r"""Compile a command and determine whether it is incomplete. Arguments: @@ -100,7 +99,7 @@ def compile_command(source, filename="", symbol="single"): syntax error (OverflowError and ValueError can be produced by malformed literals). """ - return _maybe_compile(_compile, source, filename, symbol) + return _maybe_compile(_compile, source, filename, symbol, flags) class Compile: """Instances of this class behave much like the built-in compile @@ -152,4 +151,4 @@ def __call__(self, source, filename="", symbol="single"): syntax error (OverflowError and ValueError can be produced by malformed literals). """ - return _maybe_compile(self.compiler, source, filename, symbol) + return _maybe_compile(self.compiler, source, filename, symbol, flags=self.compiler.flags) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 20c617f8108d5f..d177e3dc0f5007 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -2462,7 +2462,7 @@ def test_incorrect_constructor(self): args = ("bad.py", 1, 2) self.assertRaises(TypeError, SyntaxError, "bad bad", args) - args = ("bad.py", 1, 2, 4, 5, 6, 7) + args = ("bad.py", 1, 2, 4, 5, 6, 7, 8) self.assertRaises(TypeError, SyntaxError, "bad bad", args) args = ("bad.py", 1, 2, "abcdefg", 1) diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py index c5408b37fe5629..f3abb11952dbe0 100644 --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -1189,7 +1189,7 @@ >>> with block ad something: ... pass Traceback (most recent call last): - SyntaxError: invalid syntax + SyntaxError: invalid syntax. Did you mean 'and'? >>> try ... pass @@ -1713,6 +1713,130 @@ Traceback (most recent call last): SyntaxError: expected one or more exception types +Check custom exceptions for keywords with typos + +>>> fur a in b: +... pass +Traceback (most recent call last): +SyntaxError: invalid syntax. Did you mean 'for'? + +>>> for a in b: +... pass +... elso: +... pass +Traceback (most recent call last): +SyntaxError: invalid syntax. Did you mean 'else'? + +>>> whille True: +... pass +Traceback (most recent call last): +SyntaxError: invalid syntax. Did you mean 'while'? + +>>> while True: +... pass +... elso: +... pass +Traceback (most recent call last): +SyntaxError: invalid syntax. Did you mean 'else'? + +>>> iff x > 5: +... pass +Traceback (most recent call last): +SyntaxError: invalid syntax. Did you mean 'if'? + +>>> if x: +... pass +... elseif y: +... pass +Traceback (most recent call last): +SyntaxError: invalid syntax. Did you mean 'elif'? + +>>> if x: +... pass +... elif y: +... pass +... elso: +... pass +Traceback (most recent call last): +SyntaxError: invalid syntax. Did you mean 'else'? + +>>> tyo: +... pass +... except y: +... pass +Traceback (most recent call last): +SyntaxError: invalid syntax. Did you mean 'try'? + +>>> classe MyClass: +... pass +Traceback (most recent call last): +SyntaxError: invalid syntax. Did you mean 'class'? + +>>> impor math +Traceback (most recent call last): +SyntaxError: invalid syntax. Did you mean 'import'? + +>>> form x import y +Traceback (most recent call last): +SyntaxError: invalid syntax. Did you mean 'from'? + +>>> defn calculate_sum(a, b): +... return a + b +Traceback (most recent call last): +SyntaxError: invalid syntax. Did you mean 'def'? + +>>> def foo(): +... returm result +Traceback (most recent call last): +SyntaxError: invalid syntax. Did you mean 'return'? + +>>> lamda x: x ** 2 +Traceback (most recent call last): +SyntaxError: invalid syntax. Did you mean 'lambda'? + +>>> def foo(): +... yeld i +Traceback (most recent call last): +SyntaxError: invalid syntax. Did you mean 'yield'? + +>>> def foo(): +... globel counter +Traceback (most recent call last): +SyntaxError: invalid syntax. Did you mean 'global'? + +>>> frum math import sqrt +Traceback (most recent call last): +SyntaxError: invalid syntax. Did you mean 'from'? + +>>> asynch def fetch_data(): +... pass +Traceback (most recent call last): +SyntaxError: invalid syntax. Did you mean 'async'? + +>>> async def foo(): +... awaid fetch_data() +Traceback (most recent call last): +SyntaxError: invalid syntax. Did you mean 'await'? + +>>> raisee ValueError("Error") +Traceback (most recent call last): +SyntaxError: invalid syntax. Did you mean 'raise'? + +>>> [ +... x for x +... in range(3) +... of x +... ] +Traceback (most recent call last): +SyntaxError: invalid syntax. Did you mean 'if'? + +>>> [ +... 123 fur x +... in range(3) +... if x +... ] +Traceback (most recent call last): +SyntaxError: invalid syntax. Did you mean 'for'? >>> f(a=23, a=234) Traceback (most recent call last): diff --git a/Lib/traceback.py b/Lib/traceback.py index 78c35136ea9e8c..5bff101a72ca47 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -6,6 +6,10 @@ import sys import textwrap import warnings +import codeop +import keyword +import tokenize +import io from contextlib import suppress import _colorize from _colorize import ANSIColors @@ -1090,6 +1094,7 @@ def __init__(self, exc_type, exc_value, exc_traceback, *, limit=None, self.end_offset = exc_value.end_offset self.msg = exc_value.msg self._is_syntax_error = True + self._exc_metadata = getattr(exc_value, "_metadata", None) elif exc_type and issubclass(exc_type, ImportError) and \ getattr(exc_value, "name_from", None) is not None: wrong_name = getattr(exc_value, "name_from", None) @@ -1273,6 +1278,98 @@ def format_exception_only(self, *, show_group=False, _depth=0, **kwargs): for ex in self.exceptions: yield from ex.format_exception_only(show_group=show_group, _depth=_depth+1, colorize=colorize) + def _find_keyword_typos(self): + assert self._is_syntax_error + try: + import _suggestions + except ImportError: + _suggestions = None + + # Only try to find keyword typos if there is no custom message + if self.msg != "invalid syntax" and "Perhaps you forgot a comma" not in self.msg: + return + + if not self._exc_metadata: + return + + line, offset, source = self._exc_metadata + end_line = int(self.lineno) if self.lineno is not None else 0 + lines = None + from_filename = False + + if source is None: + if self.filename: + try: + with open(self.filename) as f: + lines = f.read().splitlines() + except Exception: + line, end_line, offset = 0,1,0 + else: + from_filename = True + lines = lines if lines is not None else self.text.splitlines() + else: + lines = source.splitlines() + + error_code = lines[line -1 if line > 0 else 0:end_line] + error_code[0] = error_code[0][offset:] + error_code = textwrap.dedent('\n'.join(error_code)) + + # Do not continue if the source is too large + if len(error_code) > 1024: + return + + error_lines = error_code.splitlines() + tokens = tokenize.generate_tokens(io.StringIO(error_code).readline) + tokens_left_to_process = 10 + import difflib + for token in tokens: + start, end = token.start, token.end + if token.type != tokenize.NAME: + continue + # Only consider NAME tokens on the same line as the error + if from_filename and token.start[0]+line != end_line+1: + continue + wrong_name = token.string + if wrong_name in keyword.kwlist: + continue + + # Limit the number of valid tokens to consider to not spend + # to much time in this function + tokens_left_to_process -= 1 + if tokens_left_to_process < 0: + break + # Limit the number of possible matches to try + matches = difflib.get_close_matches(wrong_name, keyword.kwlist, n=3) + if not matches and _suggestions is not None: + suggestion = _suggestions._generate_suggestions(keyword.kwlist, wrong_name) + matches = [suggestion] if suggestion is not None else matches + for suggestion in matches: + if not suggestion or suggestion == wrong_name: + continue + # Try to replace the token with the keyword + the_lines = error_lines.copy() + the_line = the_lines[start[0] - 1][:] + chars = list(the_line) + chars[token.start[1]:token.end[1]] = suggestion + the_lines[start[0] - 1] = ''.join(chars) + code = '\n'.join(the_lines) + + # Check if it works + try: + codeop.compile_command(code, symbol="exec", flags=codeop.PyCF_ONLY_AST) + except SyntaxError: + continue + + # Keep token.line but handle offsets correctly + self.text = token.line + self.offset = token.start[1] + 1 + self.end_offset = token.end[1] + 1 + self.lineno = start[0] + self.end_lineno = end[0] + self.msg = f"invalid syntax. Did you mean '{suggestion}'?" + return + + def _format_syntax_error(self, stype, **kwargs): """Format SyntaxError exceptions (internal helper).""" # Show exactly where the problem was found. @@ -1299,6 +1396,9 @@ def _format_syntax_error(self, stype, **kwargs): # text = " foo\n" # rtext = " foo" # ltext = "foo" + with suppress(Exception): + self._find_keyword_typos() + text = self.text rtext = text.rstrip('\n') ltext = rtext.lstrip(' \n\f') spaces = len(rtext) - len(ltext) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-19-22-59-24.gh-issue-132449.xjdw4p.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-19-22-59-24.gh-issue-132449.xjdw4p.rst new file mode 100644 index 00000000000000..05603abe64de31 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-19-22-59-24.gh-issue-132449.xjdw4p.rst @@ -0,0 +1,2 @@ +Syntax errors that look like misspellings of Python keywords now provide a +helpful fix suggestion for the typo. Contributed by Pablo Galindo Salgado. diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 942b0c630e33f0..d642130eaae625 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -2668,10 +2668,10 @@ SyntaxError_init(PyObject *op, PyObject *args, PyObject *kwds) self->end_lineno = NULL; self->end_offset = NULL; - if (!PyArg_ParseTuple(info, "OOOO|OO", + if (!PyArg_ParseTuple(info, "OOOO|OOO", &self->filename, &self->lineno, &self->offset, &self->text, - &self->end_lineno, &self->end_offset)) { + &self->end_lineno, &self->end_offset, &self->metadata)) { Py_DECREF(info); return -1; } @@ -2682,6 +2682,7 @@ SyntaxError_init(PyObject *op, PyObject *args, PyObject *kwds) Py_INCREF(self->text); Py_XINCREF(self->end_lineno); Py_XINCREF(self->end_offset); + Py_XINCREF(self->metadata); Py_DECREF(info); if (self->end_lineno != NULL && self->end_offset == NULL) { @@ -2704,6 +2705,7 @@ SyntaxError_clear(PyObject *op) Py_CLEAR(self->end_offset); Py_CLEAR(self->text); Py_CLEAR(self->print_file_and_line); + Py_CLEAR(self->metadata); return BaseException_clear(op); } @@ -2727,6 +2729,7 @@ SyntaxError_traverse(PyObject *op, visitproc visit, void *arg) Py_VISIT(self->end_offset); Py_VISIT(self->text); Py_VISIT(self->print_file_and_line); + Py_VISIT(self->metadata); return BaseException_traverse(op, visit, arg); } @@ -2822,6 +2825,8 @@ static PyMemberDef SyntaxError_members[] = { {"print_file_and_line", _Py_T_OBJECT, offsetof(PySyntaxErrorObject, print_file_and_line), 0, PyDoc_STR("exception print_file_and_line")}, + {"_metadata", _Py_T_OBJECT, offsetof(PySyntaxErrorObject, metadata), 0, + PyDoc_STR("exception private metadata")}, {NULL} /* Sentinel */ }; diff --git a/Parser/action_helpers.c b/Parser/action_helpers.c index b72a69c242328a..6a825b1abd3504 100644 --- a/Parser/action_helpers.c +++ b/Parser/action_helpers.c @@ -1711,3 +1711,20 @@ _PyPegen_checked_future_import(Parser *p, identifier module, asdl_alias_seq * na } return _PyAST_ImportFrom(module, names, level, lineno, col_offset, end_lineno, end_col_offset, arena); } + +asdl_stmt_seq* +_PyPegen_register_stmts(Parser *p, asdl_stmt_seq* stmts) { + if (!p->call_invalid_rules) { + return stmts; + } + Py_ssize_t len = asdl_seq_LEN(stmts); + if (len == 0) { + return stmts; + } + stmt_ty last_stmt = asdl_seq_GET(stmts, len - 1); + p->last_stmt_location.lineno = last_stmt->lineno; + p->last_stmt_location.col_offset = last_stmt->col_offset; + p->last_stmt_location.end_lineno = last_stmt->end_lineno; + p->last_stmt_location.end_col_offset = last_stmt->end_col_offset; + return stmts; +} diff --git a/Parser/parser.c b/Parser/parser.c index f39ad950e168b3..35a057af37e9e9 100644 --- a/Parser/parser.c +++ b/Parser/parser.c @@ -90,428 +90,429 @@ static char *soft_keywords[] = { #define func_type_type 1003 #define statements_type 1004 #define statement_type 1005 -#define statement_newline_type 1006 -#define simple_stmts_type 1007 -#define simple_stmt_type 1008 -#define compound_stmt_type 1009 -#define assignment_type 1010 -#define annotated_rhs_type 1011 -#define augassign_type 1012 -#define return_stmt_type 1013 -#define raise_stmt_type 1014 -#define pass_stmt_type 1015 -#define break_stmt_type 1016 -#define continue_stmt_type 1017 -#define global_stmt_type 1018 -#define nonlocal_stmt_type 1019 -#define del_stmt_type 1020 -#define yield_stmt_type 1021 -#define assert_stmt_type 1022 -#define import_stmt_type 1023 -#define import_name_type 1024 -#define import_from_type 1025 -#define import_from_targets_type 1026 -#define import_from_as_names_type 1027 -#define import_from_as_name_type 1028 -#define dotted_as_names_type 1029 -#define dotted_as_name_type 1030 -#define dotted_name_type 1031 // Left-recursive -#define block_type 1032 -#define decorators_type 1033 -#define class_def_type 1034 -#define class_def_raw_type 1035 -#define function_def_type 1036 -#define function_def_raw_type 1037 -#define params_type 1038 -#define parameters_type 1039 -#define slash_no_default_type 1040 -#define slash_with_default_type 1041 -#define star_etc_type 1042 -#define kwds_type 1043 -#define param_no_default_type 1044 -#define param_no_default_star_annotation_type 1045 -#define param_with_default_type 1046 -#define param_maybe_default_type 1047 -#define param_type 1048 -#define param_star_annotation_type 1049 -#define annotation_type 1050 -#define star_annotation_type 1051 -#define default_type 1052 -#define if_stmt_type 1053 -#define elif_stmt_type 1054 -#define else_block_type 1055 -#define while_stmt_type 1056 -#define for_stmt_type 1057 -#define with_stmt_type 1058 -#define with_item_type 1059 -#define try_stmt_type 1060 -#define except_block_type 1061 -#define except_star_block_type 1062 -#define finally_block_type 1063 -#define match_stmt_type 1064 -#define subject_expr_type 1065 -#define case_block_type 1066 -#define guard_type 1067 -#define patterns_type 1068 -#define pattern_type 1069 -#define as_pattern_type 1070 -#define or_pattern_type 1071 -#define closed_pattern_type 1072 -#define literal_pattern_type 1073 -#define literal_expr_type 1074 -#define complex_number_type 1075 -#define signed_number_type 1076 -#define signed_real_number_type 1077 -#define real_number_type 1078 -#define imaginary_number_type 1079 -#define capture_pattern_type 1080 -#define pattern_capture_target_type 1081 -#define wildcard_pattern_type 1082 -#define value_pattern_type 1083 -#define attr_type 1084 // Left-recursive -#define name_or_attr_type 1085 // Left-recursive -#define group_pattern_type 1086 -#define sequence_pattern_type 1087 -#define open_sequence_pattern_type 1088 -#define maybe_sequence_pattern_type 1089 -#define maybe_star_pattern_type 1090 -#define star_pattern_type 1091 -#define mapping_pattern_type 1092 -#define items_pattern_type 1093 -#define key_value_pattern_type 1094 -#define double_star_pattern_type 1095 -#define class_pattern_type 1096 -#define positional_patterns_type 1097 -#define keyword_patterns_type 1098 -#define keyword_pattern_type 1099 -#define type_alias_type 1100 -#define type_params_type 1101 -#define type_param_seq_type 1102 -#define type_param_type 1103 -#define type_param_bound_type 1104 -#define type_param_default_type 1105 -#define type_param_starred_default_type 1106 -#define expressions_type 1107 -#define expression_type 1108 -#define yield_expr_type 1109 -#define star_expressions_type 1110 -#define star_expression_type 1111 -#define star_named_expressions_type 1112 -#define star_named_expression_type 1113 -#define assignment_expression_type 1114 -#define named_expression_type 1115 -#define disjunction_type 1116 -#define conjunction_type 1117 -#define inversion_type 1118 -#define comparison_type 1119 -#define compare_op_bitwise_or_pair_type 1120 -#define eq_bitwise_or_type 1121 -#define noteq_bitwise_or_type 1122 -#define lte_bitwise_or_type 1123 -#define lt_bitwise_or_type 1124 -#define gte_bitwise_or_type 1125 -#define gt_bitwise_or_type 1126 -#define notin_bitwise_or_type 1127 -#define in_bitwise_or_type 1128 -#define isnot_bitwise_or_type 1129 -#define is_bitwise_or_type 1130 -#define bitwise_or_type 1131 // Left-recursive -#define bitwise_xor_type 1132 // Left-recursive -#define bitwise_and_type 1133 // Left-recursive -#define shift_expr_type 1134 // Left-recursive -#define sum_type 1135 // Left-recursive -#define term_type 1136 // Left-recursive -#define factor_type 1137 -#define power_type 1138 -#define await_primary_type 1139 -#define primary_type 1140 // Left-recursive -#define slices_type 1141 -#define slice_type 1142 -#define atom_type 1143 -#define group_type 1144 -#define lambdef_type 1145 -#define lambda_params_type 1146 -#define lambda_parameters_type 1147 -#define lambda_slash_no_default_type 1148 -#define lambda_slash_with_default_type 1149 -#define lambda_star_etc_type 1150 -#define lambda_kwds_type 1151 -#define lambda_param_no_default_type 1152 -#define lambda_param_with_default_type 1153 -#define lambda_param_maybe_default_type 1154 -#define lambda_param_type 1155 -#define fstring_middle_type 1156 -#define fstring_replacement_field_type 1157 -#define fstring_conversion_type 1158 -#define fstring_full_format_spec_type 1159 -#define fstring_format_spec_type 1160 -#define fstring_type 1161 -#define string_type 1162 -#define strings_type 1163 -#define list_type 1164 -#define tuple_type 1165 -#define set_type 1166 -#define dict_type 1167 -#define double_starred_kvpairs_type 1168 -#define double_starred_kvpair_type 1169 -#define kvpair_type 1170 -#define for_if_clauses_type 1171 -#define for_if_clause_type 1172 -#define listcomp_type 1173 -#define setcomp_type 1174 -#define genexp_type 1175 -#define dictcomp_type 1176 -#define arguments_type 1177 -#define args_type 1178 -#define kwargs_type 1179 -#define starred_expression_type 1180 -#define kwarg_or_starred_type 1181 -#define kwarg_or_double_starred_type 1182 -#define star_targets_type 1183 -#define star_targets_list_seq_type 1184 -#define star_targets_tuple_seq_type 1185 -#define star_target_type 1186 -#define target_with_star_atom_type 1187 -#define star_atom_type 1188 -#define single_target_type 1189 -#define single_subscript_attribute_target_type 1190 -#define t_primary_type 1191 // Left-recursive -#define t_lookahead_type 1192 -#define del_targets_type 1193 -#define del_target_type 1194 -#define del_t_atom_type 1195 -#define type_expressions_type 1196 -#define func_type_comment_type 1197 -#define invalid_arguments_type 1198 -#define invalid_kwarg_type 1199 -#define expression_without_invalid_type 1200 -#define invalid_legacy_expression_type 1201 -#define invalid_type_param_type 1202 -#define invalid_expression_type 1203 -#define invalid_named_expression_type 1204 -#define invalid_assignment_type 1205 -#define invalid_ann_assign_target_type 1206 -#define invalid_del_stmt_type 1207 -#define invalid_block_type 1208 -#define invalid_comprehension_type 1209 -#define invalid_dict_comprehension_type 1210 -#define invalid_parameters_type 1211 -#define invalid_default_type 1212 -#define invalid_star_etc_type 1213 -#define invalid_kwds_type 1214 -#define invalid_parameters_helper_type 1215 -#define invalid_lambda_parameters_type 1216 -#define invalid_lambda_parameters_helper_type 1217 -#define invalid_lambda_star_etc_type 1218 -#define invalid_lambda_kwds_type 1219 -#define invalid_double_type_comments_type 1220 -#define invalid_with_item_type 1221 -#define invalid_for_if_clause_type 1222 -#define invalid_for_target_type 1223 -#define invalid_group_type 1224 -#define invalid_import_type 1225 -#define invalid_import_from_targets_type 1226 -#define invalid_with_stmt_type 1227 -#define invalid_with_stmt_indent_type 1228 -#define invalid_try_stmt_type 1229 -#define invalid_except_stmt_type 1230 -#define invalid_except_star_stmt_type 1231 -#define invalid_finally_stmt_type 1232 -#define invalid_except_stmt_indent_type 1233 -#define invalid_except_star_stmt_indent_type 1234 -#define invalid_match_stmt_type 1235 -#define invalid_case_block_type 1236 -#define invalid_as_pattern_type 1237 -#define invalid_class_pattern_type 1238 -#define invalid_class_argument_pattern_type 1239 -#define invalid_if_stmt_type 1240 -#define invalid_elif_stmt_type 1241 -#define invalid_else_stmt_type 1242 -#define invalid_while_stmt_type 1243 -#define invalid_for_stmt_type 1244 -#define invalid_def_raw_type 1245 -#define invalid_class_def_raw_type 1246 -#define invalid_double_starred_kvpairs_type 1247 -#define invalid_kvpair_type 1248 -#define invalid_starred_expression_unpacking_type 1249 -#define invalid_starred_expression_type 1250 -#define invalid_replacement_field_type 1251 -#define invalid_conversion_character_type 1252 -#define invalid_arithmetic_type 1253 -#define invalid_factor_type 1254 -#define invalid_type_params_type 1255 -#define _loop0_1_type 1256 -#define _loop1_2_type 1257 -#define _loop0_3_type 1258 -#define _gather_4_type 1259 -#define _tmp_5_type 1260 -#define _tmp_6_type 1261 -#define _tmp_7_type 1262 -#define _tmp_8_type 1263 -#define _tmp_9_type 1264 -#define _tmp_10_type 1265 -#define _tmp_11_type 1266 -#define _loop1_12_type 1267 -#define _tmp_13_type 1268 -#define _loop0_14_type 1269 -#define _gather_15_type 1270 -#define _tmp_16_type 1271 -#define _tmp_17_type 1272 -#define _loop0_18_type 1273 -#define _loop1_19_type 1274 -#define _loop0_20_type 1275 -#define _gather_21_type 1276 -#define _tmp_22_type 1277 -#define _loop0_23_type 1278 -#define _gather_24_type 1279 -#define _loop1_25_type 1280 -#define _tmp_26_type 1281 -#define _tmp_27_type 1282 -#define _loop0_28_type 1283 -#define _loop0_29_type 1284 -#define _loop1_30_type 1285 -#define _loop1_31_type 1286 -#define _loop0_32_type 1287 -#define _loop1_33_type 1288 -#define _loop0_34_type 1289 -#define _gather_35_type 1290 -#define _tmp_36_type 1291 -#define _loop1_37_type 1292 -#define _loop1_38_type 1293 -#define _loop1_39_type 1294 -#define _loop0_40_type 1295 -#define _gather_41_type 1296 -#define _tmp_42_type 1297 -#define _tmp_43_type 1298 -#define _loop0_44_type 1299 -#define _gather_45_type 1300 -#define _loop0_46_type 1301 -#define _gather_47_type 1302 -#define _tmp_48_type 1303 -#define _loop0_49_type 1304 -#define _gather_50_type 1305 -#define _loop0_51_type 1306 -#define _gather_52_type 1307 -#define _loop0_53_type 1308 -#define _gather_54_type 1309 -#define _loop1_55_type 1310 -#define _loop1_56_type 1311 -#define _loop0_57_type 1312 -#define _gather_58_type 1313 -#define _loop1_59_type 1314 -#define _loop1_60_type 1315 -#define _loop1_61_type 1316 -#define _tmp_62_type 1317 -#define _loop0_63_type 1318 -#define _gather_64_type 1319 -#define _tmp_65_type 1320 -#define _tmp_66_type 1321 -#define _tmp_67_type 1322 -#define _tmp_68_type 1323 -#define _tmp_69_type 1324 -#define _tmp_70_type 1325 -#define _loop0_71_type 1326 -#define _loop0_72_type 1327 -#define _loop1_73_type 1328 -#define _loop1_74_type 1329 -#define _loop0_75_type 1330 -#define _loop1_76_type 1331 -#define _loop0_77_type 1332 -#define _loop0_78_type 1333 -#define _loop1_79_type 1334 -#define _tmp_80_type 1335 -#define _loop0_81_type 1336 -#define _gather_82_type 1337 -#define _loop1_83_type 1338 -#define _loop0_84_type 1339 -#define _tmp_85_type 1340 -#define _loop0_86_type 1341 -#define _gather_87_type 1342 -#define _tmp_88_type 1343 -#define _loop0_89_type 1344 -#define _gather_90_type 1345 -#define _loop0_91_type 1346 -#define _gather_92_type 1347 -#define _loop0_93_type 1348 -#define _loop0_94_type 1349 -#define _gather_95_type 1350 -#define _loop1_96_type 1351 -#define _tmp_97_type 1352 -#define _loop0_98_type 1353 -#define _gather_99_type 1354 -#define _loop0_100_type 1355 -#define _gather_101_type 1356 -#define _tmp_102_type 1357 -#define _tmp_103_type 1358 -#define _loop0_104_type 1359 -#define _gather_105_type 1360 -#define _tmp_106_type 1361 -#define _tmp_107_type 1362 -#define _tmp_108_type 1363 -#define _tmp_109_type 1364 -#define _tmp_110_type 1365 -#define _loop1_111_type 1366 -#define _tmp_112_type 1367 -#define _tmp_113_type 1368 -#define _tmp_114_type 1369 -#define _tmp_115_type 1370 -#define _tmp_116_type 1371 -#define _loop0_117_type 1372 -#define _loop0_118_type 1373 -#define _tmp_119_type 1374 -#define _tmp_120_type 1375 -#define _tmp_121_type 1376 -#define _tmp_122_type 1377 -#define _tmp_123_type 1378 -#define _tmp_124_type 1379 -#define _tmp_125_type 1380 -#define _tmp_126_type 1381 -#define _tmp_127_type 1382 -#define _loop0_128_type 1383 -#define _gather_129_type 1384 -#define _tmp_130_type 1385 -#define _tmp_131_type 1386 -#define _tmp_132_type 1387 -#define _tmp_133_type 1388 -#define _loop0_134_type 1389 -#define _gather_135_type 1390 -#define _loop0_136_type 1391 -#define _gather_137_type 1392 -#define _loop0_138_type 1393 -#define _gather_139_type 1394 -#define _tmp_140_type 1395 -#define _loop0_141_type 1396 -#define _tmp_142_type 1397 -#define _tmp_143_type 1398 -#define _tmp_144_type 1399 -#define _tmp_145_type 1400 -#define _tmp_146_type 1401 -#define _tmp_147_type 1402 -#define _tmp_148_type 1403 -#define _tmp_149_type 1404 -#define _tmp_150_type 1405 -#define _tmp_151_type 1406 -#define _tmp_152_type 1407 -#define _tmp_153_type 1408 -#define _tmp_154_type 1409 -#define _tmp_155_type 1410 -#define _tmp_156_type 1411 -#define _tmp_157_type 1412 -#define _tmp_158_type 1413 -#define _tmp_159_type 1414 -#define _tmp_160_type 1415 -#define _tmp_161_type 1416 -#define _tmp_162_type 1417 -#define _tmp_163_type 1418 -#define _tmp_164_type 1419 -#define _tmp_165_type 1420 -#define _tmp_166_type 1421 -#define _tmp_167_type 1422 -#define _loop0_168_type 1423 -#define _tmp_169_type 1424 -#define _tmp_170_type 1425 -#define _tmp_171_type 1426 -#define _tmp_172_type 1427 +#define single_compound_stmt_type 1006 +#define statement_newline_type 1007 +#define simple_stmts_type 1008 +#define simple_stmt_type 1009 +#define compound_stmt_type 1010 +#define assignment_type 1011 +#define annotated_rhs_type 1012 +#define augassign_type 1013 +#define return_stmt_type 1014 +#define raise_stmt_type 1015 +#define pass_stmt_type 1016 +#define break_stmt_type 1017 +#define continue_stmt_type 1018 +#define global_stmt_type 1019 +#define nonlocal_stmt_type 1020 +#define del_stmt_type 1021 +#define yield_stmt_type 1022 +#define assert_stmt_type 1023 +#define import_stmt_type 1024 +#define import_name_type 1025 +#define import_from_type 1026 +#define import_from_targets_type 1027 +#define import_from_as_names_type 1028 +#define import_from_as_name_type 1029 +#define dotted_as_names_type 1030 +#define dotted_as_name_type 1031 +#define dotted_name_type 1032 // Left-recursive +#define block_type 1033 +#define decorators_type 1034 +#define class_def_type 1035 +#define class_def_raw_type 1036 +#define function_def_type 1037 +#define function_def_raw_type 1038 +#define params_type 1039 +#define parameters_type 1040 +#define slash_no_default_type 1041 +#define slash_with_default_type 1042 +#define star_etc_type 1043 +#define kwds_type 1044 +#define param_no_default_type 1045 +#define param_no_default_star_annotation_type 1046 +#define param_with_default_type 1047 +#define param_maybe_default_type 1048 +#define param_type 1049 +#define param_star_annotation_type 1050 +#define annotation_type 1051 +#define star_annotation_type 1052 +#define default_type 1053 +#define if_stmt_type 1054 +#define elif_stmt_type 1055 +#define else_block_type 1056 +#define while_stmt_type 1057 +#define for_stmt_type 1058 +#define with_stmt_type 1059 +#define with_item_type 1060 +#define try_stmt_type 1061 +#define except_block_type 1062 +#define except_star_block_type 1063 +#define finally_block_type 1064 +#define match_stmt_type 1065 +#define subject_expr_type 1066 +#define case_block_type 1067 +#define guard_type 1068 +#define patterns_type 1069 +#define pattern_type 1070 +#define as_pattern_type 1071 +#define or_pattern_type 1072 +#define closed_pattern_type 1073 +#define literal_pattern_type 1074 +#define literal_expr_type 1075 +#define complex_number_type 1076 +#define signed_number_type 1077 +#define signed_real_number_type 1078 +#define real_number_type 1079 +#define imaginary_number_type 1080 +#define capture_pattern_type 1081 +#define pattern_capture_target_type 1082 +#define wildcard_pattern_type 1083 +#define value_pattern_type 1084 +#define attr_type 1085 // Left-recursive +#define name_or_attr_type 1086 // Left-recursive +#define group_pattern_type 1087 +#define sequence_pattern_type 1088 +#define open_sequence_pattern_type 1089 +#define maybe_sequence_pattern_type 1090 +#define maybe_star_pattern_type 1091 +#define star_pattern_type 1092 +#define mapping_pattern_type 1093 +#define items_pattern_type 1094 +#define key_value_pattern_type 1095 +#define double_star_pattern_type 1096 +#define class_pattern_type 1097 +#define positional_patterns_type 1098 +#define keyword_patterns_type 1099 +#define keyword_pattern_type 1100 +#define type_alias_type 1101 +#define type_params_type 1102 +#define type_param_seq_type 1103 +#define type_param_type 1104 +#define type_param_bound_type 1105 +#define type_param_default_type 1106 +#define type_param_starred_default_type 1107 +#define expressions_type 1108 +#define expression_type 1109 +#define yield_expr_type 1110 +#define star_expressions_type 1111 +#define star_expression_type 1112 +#define star_named_expressions_type 1113 +#define star_named_expression_type 1114 +#define assignment_expression_type 1115 +#define named_expression_type 1116 +#define disjunction_type 1117 +#define conjunction_type 1118 +#define inversion_type 1119 +#define comparison_type 1120 +#define compare_op_bitwise_or_pair_type 1121 +#define eq_bitwise_or_type 1122 +#define noteq_bitwise_or_type 1123 +#define lte_bitwise_or_type 1124 +#define lt_bitwise_or_type 1125 +#define gte_bitwise_or_type 1126 +#define gt_bitwise_or_type 1127 +#define notin_bitwise_or_type 1128 +#define in_bitwise_or_type 1129 +#define isnot_bitwise_or_type 1130 +#define is_bitwise_or_type 1131 +#define bitwise_or_type 1132 // Left-recursive +#define bitwise_xor_type 1133 // Left-recursive +#define bitwise_and_type 1134 // Left-recursive +#define shift_expr_type 1135 // Left-recursive +#define sum_type 1136 // Left-recursive +#define term_type 1137 // Left-recursive +#define factor_type 1138 +#define power_type 1139 +#define await_primary_type 1140 +#define primary_type 1141 // Left-recursive +#define slices_type 1142 +#define slice_type 1143 +#define atom_type 1144 +#define group_type 1145 +#define lambdef_type 1146 +#define lambda_params_type 1147 +#define lambda_parameters_type 1148 +#define lambda_slash_no_default_type 1149 +#define lambda_slash_with_default_type 1150 +#define lambda_star_etc_type 1151 +#define lambda_kwds_type 1152 +#define lambda_param_no_default_type 1153 +#define lambda_param_with_default_type 1154 +#define lambda_param_maybe_default_type 1155 +#define lambda_param_type 1156 +#define fstring_middle_type 1157 +#define fstring_replacement_field_type 1158 +#define fstring_conversion_type 1159 +#define fstring_full_format_spec_type 1160 +#define fstring_format_spec_type 1161 +#define fstring_type 1162 +#define string_type 1163 +#define strings_type 1164 +#define list_type 1165 +#define tuple_type 1166 +#define set_type 1167 +#define dict_type 1168 +#define double_starred_kvpairs_type 1169 +#define double_starred_kvpair_type 1170 +#define kvpair_type 1171 +#define for_if_clauses_type 1172 +#define for_if_clause_type 1173 +#define listcomp_type 1174 +#define setcomp_type 1175 +#define genexp_type 1176 +#define dictcomp_type 1177 +#define arguments_type 1178 +#define args_type 1179 +#define kwargs_type 1180 +#define starred_expression_type 1181 +#define kwarg_or_starred_type 1182 +#define kwarg_or_double_starred_type 1183 +#define star_targets_type 1184 +#define star_targets_list_seq_type 1185 +#define star_targets_tuple_seq_type 1186 +#define star_target_type 1187 +#define target_with_star_atom_type 1188 +#define star_atom_type 1189 +#define single_target_type 1190 +#define single_subscript_attribute_target_type 1191 +#define t_primary_type 1192 // Left-recursive +#define t_lookahead_type 1193 +#define del_targets_type 1194 +#define del_target_type 1195 +#define del_t_atom_type 1196 +#define type_expressions_type 1197 +#define func_type_comment_type 1198 +#define invalid_arguments_type 1199 +#define invalid_kwarg_type 1200 +#define expression_without_invalid_type 1201 +#define invalid_legacy_expression_type 1202 +#define invalid_type_param_type 1203 +#define invalid_expression_type 1204 +#define invalid_named_expression_type 1205 +#define invalid_assignment_type 1206 +#define invalid_ann_assign_target_type 1207 +#define invalid_del_stmt_type 1208 +#define invalid_block_type 1209 +#define invalid_comprehension_type 1210 +#define invalid_dict_comprehension_type 1211 +#define invalid_parameters_type 1212 +#define invalid_default_type 1213 +#define invalid_star_etc_type 1214 +#define invalid_kwds_type 1215 +#define invalid_parameters_helper_type 1216 +#define invalid_lambda_parameters_type 1217 +#define invalid_lambda_parameters_helper_type 1218 +#define invalid_lambda_star_etc_type 1219 +#define invalid_lambda_kwds_type 1220 +#define invalid_double_type_comments_type 1221 +#define invalid_with_item_type 1222 +#define invalid_for_if_clause_type 1223 +#define invalid_for_target_type 1224 +#define invalid_group_type 1225 +#define invalid_import_type 1226 +#define invalid_import_from_targets_type 1227 +#define invalid_with_stmt_type 1228 +#define invalid_with_stmt_indent_type 1229 +#define invalid_try_stmt_type 1230 +#define invalid_except_stmt_type 1231 +#define invalid_except_star_stmt_type 1232 +#define invalid_finally_stmt_type 1233 +#define invalid_except_stmt_indent_type 1234 +#define invalid_except_star_stmt_indent_type 1235 +#define invalid_match_stmt_type 1236 +#define invalid_case_block_type 1237 +#define invalid_as_pattern_type 1238 +#define invalid_class_pattern_type 1239 +#define invalid_class_argument_pattern_type 1240 +#define invalid_if_stmt_type 1241 +#define invalid_elif_stmt_type 1242 +#define invalid_else_stmt_type 1243 +#define invalid_while_stmt_type 1244 +#define invalid_for_stmt_type 1245 +#define invalid_def_raw_type 1246 +#define invalid_class_def_raw_type 1247 +#define invalid_double_starred_kvpairs_type 1248 +#define invalid_kvpair_type 1249 +#define invalid_starred_expression_unpacking_type 1250 +#define invalid_starred_expression_type 1251 +#define invalid_replacement_field_type 1252 +#define invalid_conversion_character_type 1253 +#define invalid_arithmetic_type 1254 +#define invalid_factor_type 1255 +#define invalid_type_params_type 1256 +#define _loop0_1_type 1257 +#define _loop1_2_type 1258 +#define _loop0_3_type 1259 +#define _gather_4_type 1260 +#define _tmp_5_type 1261 +#define _tmp_6_type 1262 +#define _tmp_7_type 1263 +#define _tmp_8_type 1264 +#define _tmp_9_type 1265 +#define _tmp_10_type 1266 +#define _tmp_11_type 1267 +#define _loop1_12_type 1268 +#define _tmp_13_type 1269 +#define _loop0_14_type 1270 +#define _gather_15_type 1271 +#define _tmp_16_type 1272 +#define _tmp_17_type 1273 +#define _loop0_18_type 1274 +#define _loop1_19_type 1275 +#define _loop0_20_type 1276 +#define _gather_21_type 1277 +#define _tmp_22_type 1278 +#define _loop0_23_type 1279 +#define _gather_24_type 1280 +#define _loop1_25_type 1281 +#define _tmp_26_type 1282 +#define _tmp_27_type 1283 +#define _loop0_28_type 1284 +#define _loop0_29_type 1285 +#define _loop1_30_type 1286 +#define _loop1_31_type 1287 +#define _loop0_32_type 1288 +#define _loop1_33_type 1289 +#define _loop0_34_type 1290 +#define _gather_35_type 1291 +#define _tmp_36_type 1292 +#define _loop1_37_type 1293 +#define _loop1_38_type 1294 +#define _loop1_39_type 1295 +#define _loop0_40_type 1296 +#define _gather_41_type 1297 +#define _tmp_42_type 1298 +#define _tmp_43_type 1299 +#define _loop0_44_type 1300 +#define _gather_45_type 1301 +#define _loop0_46_type 1302 +#define _gather_47_type 1303 +#define _tmp_48_type 1304 +#define _loop0_49_type 1305 +#define _gather_50_type 1306 +#define _loop0_51_type 1307 +#define _gather_52_type 1308 +#define _loop0_53_type 1309 +#define _gather_54_type 1310 +#define _loop1_55_type 1311 +#define _loop1_56_type 1312 +#define _loop0_57_type 1313 +#define _gather_58_type 1314 +#define _loop1_59_type 1315 +#define _loop1_60_type 1316 +#define _loop1_61_type 1317 +#define _tmp_62_type 1318 +#define _loop0_63_type 1319 +#define _gather_64_type 1320 +#define _tmp_65_type 1321 +#define _tmp_66_type 1322 +#define _tmp_67_type 1323 +#define _tmp_68_type 1324 +#define _tmp_69_type 1325 +#define _tmp_70_type 1326 +#define _loop0_71_type 1327 +#define _loop0_72_type 1328 +#define _loop1_73_type 1329 +#define _loop1_74_type 1330 +#define _loop0_75_type 1331 +#define _loop1_76_type 1332 +#define _loop0_77_type 1333 +#define _loop0_78_type 1334 +#define _loop1_79_type 1335 +#define _tmp_80_type 1336 +#define _loop0_81_type 1337 +#define _gather_82_type 1338 +#define _loop1_83_type 1339 +#define _loop0_84_type 1340 +#define _tmp_85_type 1341 +#define _loop0_86_type 1342 +#define _gather_87_type 1343 +#define _tmp_88_type 1344 +#define _loop0_89_type 1345 +#define _gather_90_type 1346 +#define _loop0_91_type 1347 +#define _gather_92_type 1348 +#define _loop0_93_type 1349 +#define _loop0_94_type 1350 +#define _gather_95_type 1351 +#define _loop1_96_type 1352 +#define _tmp_97_type 1353 +#define _loop0_98_type 1354 +#define _gather_99_type 1355 +#define _loop0_100_type 1356 +#define _gather_101_type 1357 +#define _tmp_102_type 1358 +#define _tmp_103_type 1359 +#define _loop0_104_type 1360 +#define _gather_105_type 1361 +#define _tmp_106_type 1362 +#define _tmp_107_type 1363 +#define _tmp_108_type 1364 +#define _tmp_109_type 1365 +#define _tmp_110_type 1366 +#define _loop1_111_type 1367 +#define _tmp_112_type 1368 +#define _tmp_113_type 1369 +#define _tmp_114_type 1370 +#define _tmp_115_type 1371 +#define _tmp_116_type 1372 +#define _loop0_117_type 1373 +#define _loop0_118_type 1374 +#define _tmp_119_type 1375 +#define _tmp_120_type 1376 +#define _tmp_121_type 1377 +#define _tmp_122_type 1378 +#define _tmp_123_type 1379 +#define _tmp_124_type 1380 +#define _tmp_125_type 1381 +#define _tmp_126_type 1382 +#define _tmp_127_type 1383 +#define _loop0_128_type 1384 +#define _gather_129_type 1385 +#define _tmp_130_type 1386 +#define _tmp_131_type 1387 +#define _tmp_132_type 1388 +#define _tmp_133_type 1389 +#define _loop0_134_type 1390 +#define _gather_135_type 1391 +#define _loop0_136_type 1392 +#define _gather_137_type 1393 +#define _loop0_138_type 1394 +#define _gather_139_type 1395 +#define _tmp_140_type 1396 +#define _loop0_141_type 1397 +#define _tmp_142_type 1398 +#define _tmp_143_type 1399 +#define _tmp_144_type 1400 +#define _tmp_145_type 1401 +#define _tmp_146_type 1402 +#define _tmp_147_type 1403 +#define _tmp_148_type 1404 +#define _tmp_149_type 1405 +#define _tmp_150_type 1406 +#define _tmp_151_type 1407 +#define _tmp_152_type 1408 +#define _tmp_153_type 1409 +#define _tmp_154_type 1410 +#define _tmp_155_type 1411 +#define _tmp_156_type 1412 +#define _tmp_157_type 1413 +#define _tmp_158_type 1414 +#define _tmp_159_type 1415 +#define _tmp_160_type 1416 +#define _tmp_161_type 1417 +#define _tmp_162_type 1418 +#define _tmp_163_type 1419 +#define _tmp_164_type 1420 +#define _tmp_165_type 1421 +#define _tmp_166_type 1422 +#define _tmp_167_type 1423 +#define _loop0_168_type 1424 +#define _tmp_169_type 1425 +#define _tmp_170_type 1426 +#define _tmp_171_type 1427 +#define _tmp_172_type 1428 static mod_ty file_rule(Parser *p); static mod_ty interactive_rule(Parser *p); @@ -519,6 +520,7 @@ static mod_ty eval_rule(Parser *p); static mod_ty func_type_rule(Parser *p); static asdl_stmt_seq* statements_rule(Parser *p); static asdl_stmt_seq* statement_rule(Parser *p); +static asdl_stmt_seq* single_compound_stmt_rule(Parser *p); static asdl_stmt_seq* statement_newline_rule(Parser *p); static asdl_stmt_seq* simple_stmts_rule(Parser *p); static stmt_ty simple_stmt_rule(Parser *p); @@ -1167,7 +1169,7 @@ statements_rule(Parser *p) ) { D(fprintf(stderr, "%*c+ statements[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "statement+")); - _res = ( asdl_stmt_seq* ) _PyPegen_seq_flatten ( p , a ); + _res = _PyPegen_register_stmts ( p , ( asdl_stmt_seq* ) _PyPegen_seq_flatten ( p , a ) ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; p->level--; @@ -1252,7 +1254,50 @@ statement_rule(Parser *p) return _res; } -// statement_newline: compound_stmt NEWLINE | simple_stmts | NEWLINE | $ +// single_compound_stmt: compound_stmt +static asdl_stmt_seq* +single_compound_stmt_rule(Parser *p) +{ + if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + asdl_stmt_seq* _res = NULL; + int _mark = p->mark; + { // compound_stmt + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> single_compound_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "compound_stmt")); + stmt_ty a; + if ( + (a = compound_stmt_rule(p)) // compound_stmt + ) + { + D(fprintf(stderr, "%*c+ single_compound_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "compound_stmt")); + _res = _PyPegen_register_stmts ( p , ( asdl_stmt_seq* ) _PyPegen_singleton_seq ( p , a ) ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s single_compound_stmt[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "compound_stmt")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// statement_newline: single_compound_stmt NEWLINE | simple_stmts | NEWLINE | $ static asdl_stmt_seq* statement_newline_rule(Parser *p) { @@ -1274,22 +1319,22 @@ statement_newline_rule(Parser *p) UNUSED(_start_lineno); // Only used by EXTRA macro int _start_col_offset = p->tokens[_mark]->col_offset; UNUSED(_start_col_offset); // Only used by EXTRA macro - { // compound_stmt NEWLINE + { // single_compound_stmt NEWLINE if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> statement_newline[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "compound_stmt NEWLINE")); - stmt_ty a; + D(fprintf(stderr, "%*c> statement_newline[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "single_compound_stmt NEWLINE")); + asdl_stmt_seq* a; Token * newline_var; if ( - (a = compound_stmt_rule(p)) // compound_stmt + (a = single_compound_stmt_rule(p)) // single_compound_stmt && (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) { - D(fprintf(stderr, "%*c+ statement_newline[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "compound_stmt NEWLINE")); - _res = ( asdl_stmt_seq* ) _PyPegen_singleton_seq ( p , a ); + D(fprintf(stderr, "%*c+ statement_newline[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "single_compound_stmt NEWLINE")); + _res = a; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; p->level--; @@ -1299,7 +1344,7 @@ statement_newline_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s statement_newline[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "compound_stmt NEWLINE")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "single_compound_stmt NEWLINE")); } { // simple_stmts if (p->error_indicator) { diff --git a/Parser/pegen.c b/Parser/pegen.c index 75fdd467e55045..3efeba78450d1a 100644 --- a/Parser/pegen.c +++ b/Parser/pegen.c @@ -799,7 +799,7 @@ compute_parser_flags(PyCompilerFlags *flags) Parser * _PyPegen_Parser_New(struct tok_state *tok, int start_rule, int flags, - int feature_version, int *errcode, PyArena *arena) + int feature_version, int *errcode, const char* source, PyArena *arena) { Parser *p = PyMem_Malloc(sizeof(Parser)); if (p == NULL) { @@ -847,6 +847,10 @@ _PyPegen_Parser_New(struct tok_state *tok, int start_rule, int flags, p->known_err_token = NULL; p->level = 0; p->call_invalid_rules = 0; + p->last_stmt_location.lineno = 0; + p->last_stmt_location.col_offset = 0; + p->last_stmt_location.end_lineno = 0; + p->last_stmt_location.end_col_offset = 0; #ifdef Py_DEBUG p->debug = _Py_GetConfig()->parser_debug; #endif @@ -868,6 +872,10 @@ _PyPegen_Parser_Free(Parser *p) static void reset_parser_state_for_error_pass(Parser *p) { + p->last_stmt_location.lineno = 0; + p->last_stmt_location.col_offset = 0; + p->last_stmt_location.end_lineno = 0; + p->last_stmt_location.end_col_offset = 0; for (int i = 0; i < p->fill; i++) { p->tokens[i]->memo = NULL; } @@ -884,6 +892,51 @@ _is_end_of_source(Parser *p) { return err == E_EOF || err == E_EOFS || err == E_EOLS; } +static void +_PyPegen_set_syntax_error_metadata(Parser *p) { + PyObject *exc = PyErr_GetRaisedException(); + if (!exc || !PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_SyntaxError)) { + PyErr_SetRaisedException(exc); + return; + } + const char *source = NULL; + if (p->tok->str != NULL) { + source = p->tok->str; + } + if (!source && p->tok->fp_interactive && p->tok->interactive_src_start) { + source = p->tok->interactive_src_start; + } + PyObject* the_source = NULL; + if (source) { + if (p->tok->encoding == NULL) { + the_source = PyUnicode_FromString(source); + } else { + the_source = PyUnicode_Decode(source, strlen(source), p->tok->encoding, NULL); + } + } + if (!the_source) { + PyErr_Clear(); + the_source = Py_None; + Py_INCREF(the_source); + } + PyObject* metadata = Py_BuildValue( + "(iiN)", + p->last_stmt_location.lineno, + p->last_stmt_location.col_offset, + the_source // N gives ownership to metadata + ); + if (!metadata) { + Py_DECREF(the_source); + PyErr_Clear(); + return; + } + PySyntaxErrorObject *syntax_error = (PySyntaxErrorObject *)exc; + + Py_XDECREF(syntax_error->metadata); + syntax_error->metadata = metadata; + PyErr_SetRaisedException(exc); +} + void * _PyPegen_run_parser(Parser *p) { @@ -907,6 +960,11 @@ _PyPegen_run_parser(Parser *p) // Set SyntaxErrors accordingly depending on the parser/tokenizer status at the failure // point. _Pypegen_set_syntax_error(p, last_token); + + // Set the metadata in the exception from p->last_stmt_location + if (PyErr_ExceptionMatches(PyExc_SyntaxError)) { + _PyPegen_set_syntax_error_metadata(p); + } return NULL; } @@ -955,7 +1013,7 @@ _PyPegen_run_parser_from_file_pointer(FILE *fp, int start_rule, PyObject *filena int parser_flags = compute_parser_flags(flags); Parser *p = _PyPegen_Parser_New(tok, start_rule, parser_flags, PY_MINOR_VERSION, - errcode, arena); + errcode, NULL, arena); if (p == NULL) { goto error; } @@ -1005,7 +1063,7 @@ _PyPegen_run_parser_from_string(const char *str, int start_rule, PyObject *filen int feature_version = flags && (flags->cf_flags & PyCF_ONLY_AST) ? flags->cf_feature_version : PY_MINOR_VERSION; Parser *p = _PyPegen_Parser_New(tok, start_rule, parser_flags, feature_version, - NULL, arena); + NULL, str, arena); if (p == NULL) { goto error; } diff --git a/Parser/pegen.h b/Parser/pegen.h index 37d6ea988d2af4..e219aa0359e578 100644 --- a/Parser/pegen.h +++ b/Parser/pegen.h @@ -55,6 +55,13 @@ typedef struct { size_t num_items; } growable_comment_array; +typedef struct { + int lineno; + int col_offset; + int end_lineno; + int end_col_offset; +} location; + typedef struct { struct tok_state *tok; Token **tokens; @@ -78,6 +85,7 @@ typedef struct { int level; int call_invalid_rules; int debug; + location last_stmt_location; } Parser; typedef struct { @@ -148,6 +156,7 @@ int _PyPegen_fill_token(Parser *p); expr_ty _PyPegen_name_token(Parser *p); expr_ty _PyPegen_number_token(Parser *p); void *_PyPegen_string_token(Parser *p); +PyObject *_PyPegen_set_source_in_metadata(Parser *p, Token *t); Py_ssize_t _PyPegen_byte_offset_to_character_offset_line(PyObject *line, Py_ssize_t col_offset, Py_ssize_t end_col_offset); Py_ssize_t _PyPegen_byte_offset_to_character_offset(PyObject *line, Py_ssize_t col_offset); Py_ssize_t _PyPegen_byte_offset_to_character_offset_raw(const char*, Py_ssize_t col_offset); @@ -348,10 +357,12 @@ expr_ty _PyPegen_get_last_comprehension_item(comprehension_ty comprehension); void *_PyPegen_nonparen_genexp_in_call(Parser *p, expr_ty args, asdl_comprehension_seq *comprehensions); stmt_ty _PyPegen_checked_future_import(Parser *p, identifier module, asdl_alias_seq *, int , int, int , int , int , PyArena *); +asdl_stmt_seq* _PyPegen_register_stmts(Parser *p, asdl_stmt_seq* stmts); +stmt_ty _PyPegen_register_stmt(Parser *p, stmt_ty s); // Parser API -Parser *_PyPegen_Parser_New(struct tok_state *, int, int, int, int *, PyArena *); +Parser *_PyPegen_Parser_New(struct tok_state *, int, int, int, int *, const char*, PyArena *); void _PyPegen_Parser_Free(Parser *); mod_ty _PyPegen_run_parser_from_file_pointer(FILE *, int, PyObject *, const char *, const char *, const char *, PyCompilerFlags *, int *, PyObject **,