Commit d930a704 authored by Stefan Behnel's avatar Stefan Behnel

disable async/await keywords in nested normal 'def' functions (as CPython does)

parent 471d145c
......@@ -2039,18 +2039,14 @@ def p_statement(s, ctx, first_statement = 0):
return p_async_statement(s, ctx, decorators)
else:
if s.sy == 'IDENT' and s.systring == 'async':
ident_name = s.systring
# PEP 492 enables the async/await keywords when it spots "async def ..."
s.next()
if s.sy == 'def':
s.enable_keyword('async')
s.enable_keyword('await')
result = p_async_statement(s, ctx, decorators)
s.disable_keyword('await')
s.disable_keyword('async')
return result
return p_async_statement(s, ctx, decorators)
elif decorators:
s.error("Decorators can only be followed by functions or classes")
s.put_back('IDENT', 'async')
s.put_back('IDENT', ident_name) # re-insert original token
return p_simple_statement_list(s, ctx, first_statement=first_statement)
......@@ -3072,7 +3068,25 @@ def p_def_statement(s, decorators=None, is_async_def=False):
if s.sy == '->':
s.next()
return_type_annotation = p_test(s)
# PEP 492 switches the async/await keywords off in simple "def" functions
# and on in "async def" functions
await_was_enabled = s.enable_keyword('await') if is_async_def else s.disable_keyword('await')
async_was_enabled = s.enable_keyword('async') if is_async_def else s.disable_keyword('async')
doc, body = p_suite_with_docstring(s, Ctx(level='function'))
if is_async_def:
if not async_was_enabled:
s.disable_keyword('async')
if not await_was_enabled:
s.disable_keyword('await')
else:
if async_was_enabled:
s.enable_keyword('async')
if await_was_enabled:
s.enable_keyword('await')
return Nodes.DefNode(
pos, name=name, args=args, star_arg=star_arg, starstar_arg=starstar_arg,
doc=doc, body=body, decorators=decorators, is_async_def=is_async_def,
......
......@@ -30,7 +30,6 @@ cdef class PyrexScanner(Scanner):
cdef public bint in_python_file
cdef public source_encoding
cdef set keywords
cdef public dict keywords_stack
cdef public list indentation_stack
cdef public indentation_char
cdef public int bracket_nesting_level
......@@ -58,5 +57,5 @@ cdef class PyrexScanner(Scanner):
cdef expect_indent(self)
cdef expect_dedent(self)
cdef expect_newline(self, message=*, bint ignore_semicolon=*)
cdef enable_keyword(self, name)
cdef disable_keyword(self, name)
cdef bint enable_keyword(self, name) except -1
cdef bint disable_keyword(self, name) except -1
......@@ -314,7 +314,6 @@ class PyrexScanner(Scanner):
self.in_python_file = False
self.keywords = set(pyx_reserved_words)
self.trace = trace_scanner
self.keywords_stack = {}
self.indentation_stack = [0]
self.indentation_char = None
self.bracket_nesting_level = 0
......@@ -495,16 +494,13 @@ class PyrexScanner(Scanner):
warning(useless_trailing_semicolon, "useless trailing semicolon")
def enable_keyword(self, name):
if name in self.keywords_stack:
self.keywords_stack[name] += 1
else:
self.keywords_stack[name] = 1
if name in self.keywords:
return True # was enabled before
self.keywords.add(name)
return False # was not enabled before
def disable_keyword(self, name):
count = self.keywords_stack.get(name, 1)
if count == 1:
self.keywords.discard(name)
del self.keywords_stack[name]
else:
self.keywords_stack[name] = count - 1
if name not in self.keywords:
return False # was not enabled before
self.keywords.remove(name)
return True # was enabled before
......@@ -138,6 +138,17 @@ class TokenizerRegrTest(unittest.TestCase):
self.assertEqual(type(ns['foo']()).__name__, 'coroutine')
#self.assertTrue(inspect.iscoroutinefunction(ns['foo']))
def test_syntax_async_await_as_names(self):
async def enable():
await 123
def disable():
await = 123
async = 'abc'
async def reenable():
await 432
class CoroutineTest(unittest.TestCase):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment