Skip to content

Commit 8085b80

Browse files
author
Yury Selivanov
committed
Issue 24226: Fix parsing of many sequential one-line 'def' statements.
1 parent a2c145c commit 8085b80

3 files changed

Lines changed: 51 additions & 8 deletions

File tree

Lib/test/test_coroutines.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import contextlib
2+
import inspect
23
import sys
34
import types
45
import unittest
@@ -87,6 +88,28 @@ def test_badsyntax_9(self):
8788
import test.badsyntax_async9
8889

8990

91+
class TokenizerRegrTest(unittest.TestCase):
92+
93+
def test_oneline_defs(self):
94+
buf = []
95+
for i in range(500):
96+
buf.append('def i{i}(): return {i}'.format(i=i))
97+
buf = '\n'.join(buf)
98+
99+
# Test that 500 consequent, one-line defs is OK
100+
ns = {}
101+
exec(buf, ns, ns)
102+
self.assertEqual(ns['i499'](), 499)
103+
104+
# Test that 500 consequent, one-line defs *and*
105+
# one 'async def' following them is OK
106+
buf += '\nasync def foo():\n return'
107+
ns = {}
108+
exec(buf, ns, ns)
109+
self.assertEqual(ns['i499'](), 499)
110+
self.assertTrue(inspect.iscoroutinefunction(ns['foo']))
111+
112+
90113
class CoroutineTest(unittest.TestCase):
91114

92115
def test_gen_1(self):

Lib/test/test_tokenize.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1289,6 +1289,17 @@ def mock_readline():
12891289

12901290
self.assertTrue(encoding_used, encoding)
12911291

1292+
def test_oneline_defs(self):
1293+
buf = []
1294+
for i in range(500):
1295+
buf.append('def i{i}(): return {i}'.format(i=i))
1296+
buf.append('OK')
1297+
buf = '\n'.join(buf)
1298+
1299+
# Test that 500 consequent, one-line defs is OK
1300+
toks = list(tokenize(BytesIO(buf.encode('utf-8')).readline))
1301+
self.assertEqual(toks[-2].string, 'OK') # [-1] is always ENDMARKER
1302+
12921303
def assertExactTypeEqual(self, opstr, *optypes):
12931304
tokens = list(tokenize(BytesIO(opstr.encode('utf-8')).readline))
12941305
num_optypes = len(optypes)

Parser/tokenizer.c

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1501,17 +1501,20 @@ tok_get(struct tok_state *tok, char **p_start, char **p_end)
15011501

15021502
tok_len = tok->cur - tok->start;
15031503
if (tok_len == 3 && memcmp(tok->start, "def", 3) == 0) {
1504-
1505-
if (tok->def + 1 >= MAXINDENT) {
1506-
tok->done = E_TOODEEP;
1507-
tok->cur = tok->inp;
1508-
return ERRORTOKEN;
1509-
}
1510-
15111504
if (tok->def && tok->deftypestack[tok->def] == 3) {
15121505
tok->deftypestack[tok->def] = 2;
15131506
}
1514-
else {
1507+
else if (tok->defstack[tok->def] < tok->indent) {
1508+
/* We advance defs stack only when we see "def" *and*
1509+
the indentation level was increased relative to the
1510+
previous "def". */
1511+
1512+
if (tok->def + 1 >= MAXINDENT) {
1513+
tok->done = E_TOODEEP;
1514+
tok->cur = tok->inp;
1515+
return ERRORTOKEN;
1516+
}
1517+
15151518
tok->def++;
15161519
tok->defstack[tok->def] = tok->indent;
15171520
tok->deftypestack[tok->def] = 1;
@@ -1528,6 +1531,12 @@ tok_get(struct tok_state *tok, char **p_start, char **p_end)
15281531
ahead_tok.cur - ahead_tok.start == 3 &&
15291532
memcmp(ahead_tok.start, "def", 3) == 0) {
15301533

1534+
if (tok->def + 1 >= MAXINDENT) {
1535+
tok->done = E_TOODEEP;
1536+
tok->cur = tok->inp;
1537+
return ERRORTOKEN;
1538+
}
1539+
15311540
tok->def++;
15321541
tok->defstack[tok->def] = tok->indent;
15331542
tok->deftypestack[tok->def] = 3;

0 commit comments

Comments
 (0)