Skip to content

Commit 00eb97b

Browse files
bpo-36256: Fix bug in parsermodule when parsing if statements (GH-12488)
bpo-36256: Fix bug in parsermodule when parsing if statements In the parser module, when validating nodes before starting the parsing with to create a ST in "parser_newstobject" there is a problem that appears when two arcs in the same DFA state has transitions with labels with the same type. For example, the DFA for if_stmt has a state with two labels with the same type: "elif" and "else" (type NAME). The algorithm tries one by one the arcs until the label that starts the arc transition has a label with the same type of the current child label we are trying to accept. In this case, the arc for "elif" comes before the arc for "else"and passes this test (because the current child label is "else" and has the same type as "elif"). This lead to expecting a namedexpr_test (305) instead of a colon (11). The solution is to compare also the string representation (in case there is one) of the labels to see if the transition that we have is the correct one. (cherry picked from commit 9a0000d) Co-authored-by: Pablo Galindo <[email protected]>
1 parent cba5ddf commit 00eb97b

File tree

3 files changed

+23
-5
lines changed

3 files changed

+23
-5
lines changed

Lib/test/test_parser.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,10 @@ def test_try_stmt(self):
318318
self.check_suite("try: pass\nexcept: pass\nelse: pass\n"
319319
"finally: pass\n")
320320

321+
def test_if_stmt(self):
322+
self.check_suite("if True:\n pass\nelse:\n pass\n")
323+
self.check_suite("if True:\n pass\nelif True:\n pass\nelse:\n pass\n")
324+
321325
def test_position(self):
322326
# An absolutely minimal test of position information. Better
323327
# tests would be a big project.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix bug in parsermodule when parsing a state in a DFA that has two or more
2+
arcs with labels of the same type. Patch by Pablo Galindo.

Modules/parsermodule.c

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -666,7 +666,12 @@ validate_node(node *tree)
666666
for (arc = 0; arc < dfa_state->s_narcs; ++arc) {
667667
short a_label = dfa_state->s_arc[arc].a_lbl;
668668
assert(a_label < _PyParser_Grammar.g_ll.ll_nlabels);
669-
if (_PyParser_Grammar.g_ll.ll_label[a_label].lb_type == ch_type) {
669+
670+
const char *label_str = _PyParser_Grammar.g_ll.ll_label[a_label].lb_str;
671+
if ((_PyParser_Grammar.g_ll.ll_label[a_label].lb_type == ch_type)
672+
&& ((ch->n_str == NULL) || (label_str == NULL)
673+
|| (strcmp(ch->n_str, label_str) == 0))
674+
) {
670675
/* The child is acceptable; if non-terminal, validate it recursively. */
671676
if (ISNONTERMINAL(ch_type) && !validate_node(ch))
672677
return 0;
@@ -679,17 +684,24 @@ validate_node(node *tree)
679684
/* What would this state have accepted? */
680685
{
681686
short a_label = dfa_state->s_arc->a_lbl;
682-
int next_type;
683687
if (!a_label) /* Wouldn't accept any more children */
684688
goto illegal_num_children;
685689

686-
next_type = _PyParser_Grammar.g_ll.ll_label[a_label].lb_type;
687-
if (ISNONTERMINAL(next_type))
690+
int next_type = _PyParser_Grammar.g_ll.ll_label[a_label].lb_type;
691+
const char *expected_str = _PyParser_Grammar.g_ll.ll_label[a_label].lb_str;
692+
693+
if (ISNONTERMINAL(next_type)) {
688694
PyErr_Format(parser_error, "Expected node type %d, got %d.",
689695
next_type, ch_type);
690-
else
696+
}
697+
else if (expected_str != NULL) {
698+
PyErr_Format(parser_error, "Illegal terminal: expected '%s'.",
699+
expected_str);
700+
}
701+
else {
691702
PyErr_Format(parser_error, "Illegal terminal: expected %s.",
692703
_PyParser_TokenNames[next_type]);
704+
}
693705
return 0;
694706
}
695707

0 commit comments

Comments
 (0)