Restore ability to format code with legacy usage of async as a name

Fixes #20
Fixes #42
This commit is contained in:
Łukasz Langa 2018-03-20 18:05:20 -07:00
parent 155aa71db0
commit d9c6b99073
7 changed files with 91 additions and 12 deletions

View File

@ -261,6 +261,10 @@ More details can be found in [CONTRIBUTING](CONTRIBUTING.md).
* added ability to pipe formatting from stdin to stdin (#25) * added ability to pipe formatting from stdin to stdin (#25)
* restored ability to format code with legacy usage of `async` as
a name (#20, #42)
### 18.3a2 ### 18.3a2
* changed positioning of binary operators to occur at beginning of lines * changed positioning of binary operators to occur at beginning of lines

View File

@ -486,8 +486,7 @@ def is_def(self) -> bool:
return ( return (
(first_leaf.type == token.NAME and first_leaf.value == 'def') (first_leaf.type == token.NAME and first_leaf.value == 'def')
or ( or (
first_leaf.type == token.NAME first_leaf.type == token.ASYNC
and first_leaf.value == 'async'
and second_leaf is not None and second_leaf is not None
and second_leaf.type == token.NAME and second_leaf.type == token.NAME
and second_leaf.value == 'def' and second_leaf.value == 'def'
@ -816,7 +815,7 @@ def visit_async_stmt(self, node: Node) -> Iterator[Line]:
for child in children: for child in children:
yield from self.visit(child) yield from self.visit(child)
if child.type == token.NAME and child.value == 'async': # type: ignore if child.type == token.ASYNC:
break break
internal_stmt = next(children) internal_stmt = next(children)

View File

@ -15,7 +15,7 @@ eval_input: testlist NEWLINE* ENDMARKER
decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE
decorators: decorator+ decorators: decorator+
decorated: decorators (classdef | funcdef | async_funcdef) decorated: decorators (classdef | funcdef | async_funcdef)
async_funcdef: 'async' funcdef async_funcdef: ASYNC funcdef
funcdef: 'def' NAME parameters ['->' test] ':' suite funcdef: 'def' NAME parameters ['->' test] ':' suite
parameters: '(' [typedargslist] ')' parameters: '(' [typedargslist] ')'
typedargslist: ((tfpdef ['=' test] ',')* typedargslist: ((tfpdef ['=' test] ',')*
@ -66,7 +66,7 @@ exec_stmt: 'exec' expr ['in' test [',' test]]
assert_stmt: 'assert' test [',' test] assert_stmt: 'assert' test [',' test]
compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated | async_stmt compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated | async_stmt
async_stmt: 'async' (funcdef | with_stmt | for_stmt) async_stmt: ASYNC (funcdef | with_stmt | for_stmt)
if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
while_stmt: 'while' test ':' suite ['else' ':' suite] while_stmt: 'while' test ':' suite ['else' ':' suite]
for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite] for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite]
@ -105,7 +105,7 @@ shift_expr: arith_expr (('<<'|'>>') arith_expr)*
arith_expr: term (('+'|'-') term)* arith_expr: term (('+'|'-') term)*
term: factor (('*'|'@'|'/'|'%'|'//') factor)* term: factor (('*'|'@'|'/'|'%'|'//') factor)*
factor: ('+'|'-'|'~') factor | power factor: ('+'|'-'|'~') factor | power
power: ['await'] atom trailer* ['**' factor] power: [AWAIT] atom trailer* ['**' factor]
atom: ('(' [yield_expr|testlist_gexp] ')' | atom: ('(' [yield_expr|testlist_gexp] ')' |
'[' [listmaker] ']' | '[' [listmaker] ']' |
'{' [dictsetmaker] '}' | '{' [dictsetmaker] '}' |
@ -142,7 +142,7 @@ argument: ( test [comp_for] |
star_expr ) star_expr )
comp_iter: comp_for | comp_if comp_iter: comp_for | comp_if
comp_for: ['async'] 'for' exprlist 'in' or_test [comp_iter] comp_for: [ASYNC] 'for' exprlist 'in' or_test [comp_iter]
comp_if: 'if' old_test [comp_iter] comp_if: 'if' old_test [comp_iter]
# As noted above, testlist_safe extends the syntax allowed in list # As noted above, testlist_safe extends the syntax allowed in list
@ -161,7 +161,7 @@ comp_if: 'if' old_test [comp_iter]
# #
# See https://bugs.python.org/issue27494 # See https://bugs.python.org/issue27494
old_comp_iter: old_comp_for | old_comp_if old_comp_iter: old_comp_for | old_comp_if
old_comp_for: ['async'] 'for' exprlist 'in' testlist_safe [old_comp_iter] old_comp_for: [ASYNC] 'for' exprlist 'in' testlist_safe [old_comp_iter]
old_comp_if: 'if' old_test [old_comp_iter] old_comp_if: 'if' old_test [old_comp_iter]
testlist1: test (',' test)* testlist1: test (',' test)*

Binary file not shown.

View File

@ -5,5 +5,7 @@ Reasons for forking:
- consistent handling of f-strings for users of Python < 3.6.2 - consistent handling of f-strings for users of Python < 3.6.2
- backport of BPO-33064 that fixes parsing files with trailing commas after - backport of BPO-33064 that fixes parsing files with trailing commas after
*args and **kwargs *args and **kwargs
- backport of GH-6143 that restores the ability to reformat legacy usage of
`async`
- better ability to debug (better reprs for starters) - better ability to debug (better reprs for starters)
- ability to Cythonize - ability to Cythonize

View File

@ -62,8 +62,10 @@
COMMENT = 53 COMMENT = 53
NL = 54 NL = 54
RARROW = 55 RARROW = 55
ERRORTOKEN = 56 AWAIT = 56
N_TOKENS = 57 ASYNC = 57
ERRORTOKEN = 58
N_TOKENS = 59
NT_OFFSET = 256 NT_OFFSET = 256
#--end constants-- #--end constants--

View File

@ -234,7 +234,7 @@ def compat(self, token, iterable):
for tok in iterable: for tok in iterable:
toknum, tokval = tok[:2] toknum, tokval = tok[:2]
if toknum in (NAME, NUMBER): if toknum in (NAME, NUMBER, ASYNC, AWAIT):
tokval += ' ' tokval += ' '
if toknum == INDENT: if toknum == INDENT:
@ -380,6 +380,12 @@ def generate_tokens(readline):
contline = None contline = None
indents = [0] indents = [0]
# 'stashed' and 'async_*' are used for async/await parsing
stashed = None
async_def = False
async_def_indent = 0
async_def_nl = False
while 1: # loop over lines in stream while 1: # loop over lines in stream
try: try:
line = readline() line = readline()
@ -420,6 +426,10 @@ def generate_tokens(readline):
pos = pos + 1 pos = pos + 1
if pos == max: break if pos == max: break
if stashed:
yield stashed
stashed = None
if line[pos] in '#\r\n': # skip comments or blank lines if line[pos] in '#\r\n': # skip comments or blank lines
if line[pos] == '#': if line[pos] == '#':
comment_token = line[pos:].rstrip('\r\n') comment_token = line[pos:].rstrip('\r\n')
@ -443,8 +453,18 @@ def generate_tokens(readline):
("<tokenize>", lnum, pos, line)) ("<tokenize>", lnum, pos, line))
indents = indents[:-1] indents = indents[:-1]
if async_def and async_def_indent >= indents[-1]:
async_def = False
async_def_nl = False
async_def_indent = 0
yield (DEDENT, '', (lnum, pos), (lnum, pos), line) yield (DEDENT, '', (lnum, pos), (lnum, pos), line)
if async_def and async_def_nl and async_def_indent >= indents[-1]:
async_def = False
async_def_nl = False
async_def_indent = 0
else: # continued statement else: # continued statement
if not line: if not line:
raise TokenError("EOF in multi-line statement", (lnum, 0)) raise TokenError("EOF in multi-line statement", (lnum, 0))
@ -464,10 +484,18 @@ def generate_tokens(readline):
newline = NEWLINE newline = NEWLINE
if parenlev > 0: if parenlev > 0:
newline = NL newline = NL
elif async_def:
async_def_nl = True
if stashed:
yield stashed
stashed = None
yield (newline, token, spos, epos, line) yield (newline, token, spos, epos, line)
elif initial == '#': elif initial == '#':
assert not token.endswith("\n") assert not token.endswith("\n")
if stashed:
yield stashed
stashed = None
yield (COMMENT, token, spos, epos, line) yield (COMMENT, token, spos, epos, line)
elif token in triple_quoted: elif token in triple_quoted:
endprog = endprogs[token] endprog = endprogs[token]
@ -475,6 +503,9 @@ def generate_tokens(readline):
if endmatch: # all on one line if endmatch: # all on one line
pos = endmatch.end(0) pos = endmatch.end(0)
token = line[start:pos] token = line[start:pos]
if stashed:
yield stashed
stashed = None
yield (STRING, token, spos, (lnum, pos), line) yield (STRING, token, spos, (lnum, pos), line)
else: else:
strstart = (lnum, start) # multiple lines strstart = (lnum, start) # multiple lines
@ -492,22 +523,63 @@ def generate_tokens(readline):
contline = line contline = line
break break
else: # ordinary string else: # ordinary string
if stashed:
yield stashed
stashed = None
yield (STRING, token, spos, epos, line) yield (STRING, token, spos, epos, line)
elif initial in namechars: # ordinary name elif initial in namechars: # ordinary name
yield (NAME, token, spos, epos, line) if token in ('async', 'await'):
if async_def:
yield (ASYNC if token == 'async' else AWAIT,
token, spos, epos, line)
continue
tok = (NAME, token, spos, epos, line)
if token == 'async' and not stashed:
stashed = tok
continue
if token == 'def':
if (stashed
and stashed[0] == NAME
and stashed[1] == 'async'):
async_def = True
async_def_indent = indents[-1]
yield (ASYNC, stashed[1],
stashed[2], stashed[3],
stashed[4])
stashed = None
if stashed:
yield stashed
stashed = None
yield tok
elif initial == '\\': # continued stmt elif initial == '\\': # continued stmt
# This yield is new; needed for better idempotency: # This yield is new; needed for better idempotency:
if stashed:
yield stashed
stashed = None
yield (NL, token, spos, (lnum, pos), line) yield (NL, token, spos, (lnum, pos), line)
continued = 1 continued = 1
else: else:
if initial in '([{': parenlev = parenlev + 1 if initial in '([{': parenlev = parenlev + 1
elif initial in ')]}': parenlev = parenlev - 1 elif initial in ')]}': parenlev = parenlev - 1
if stashed:
yield stashed
stashed = None
yield (OP, token, spos, epos, line) yield (OP, token, spos, epos, line)
else: else:
yield (ERRORTOKEN, line[pos], yield (ERRORTOKEN, line[pos],
(lnum, pos), (lnum, pos+1), line) (lnum, pos), (lnum, pos+1), line)
pos = pos + 1 pos = pos + 1
if stashed:
yield stashed
stashed = None
for indent in indents[1:]: # pop remaining indent levels for indent in indents[1:]: # pop remaining indent levels
yield (DEDENT, '', (lnum, 0), (lnum, 0), '') yield (DEDENT, '', (lnum, 0), (lnum, 0), '')
yield (ENDMARKER, '', (lnum, 0), (lnum, 0), '') yield (ENDMARKER, '', (lnum, 0), (lnum, 0), '')