Skip to content

Commit 28f4e91

Browse files
committed
Add support for async/await syntax in Python 3.5
1 parent 6601971 commit 28f4e91

6 files changed

Lines changed: 53 additions & 4 deletions

File tree

src/Language/Python/Common/AST.hs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,10 @@ data Statement annot
229229
, for_else :: Suite annot -- ^ Else clause.
230230
, stmt_annot :: annot
231231
}
232+
| AsyncFor
233+
{ for_stmt :: Statement annot -- ^ For statement
234+
, stmt_annot :: annot
235+
}
232236
-- | Function definition.
233237
| Fun
234238
{ fun_name :: Ident annot -- ^ Function name.
@@ -237,6 +241,10 @@ data Statement annot
237241
, fun_body :: Suite annot -- ^ Function body.
238242
, stmt_annot :: annot
239243
}
244+
| AsyncFun
245+
{ fun_def :: Statement annot -- ^ Function definition (Fun)
246+
, stmt_annot :: annot
247+
}
240248
-- | Class definition.
241249
| Class
242250
{ class_name :: Ident annot -- ^ Class name.
@@ -293,6 +301,10 @@ data Statement annot
293301
, with_body :: Suite annot -- ^ Suite to be managed.
294302
, stmt_annot :: annot
295303
}
304+
| AsyncWith
305+
{ with_stmt :: Statement annot -- ^ With statement
306+
, stmt_annot :: annot
307+
}
296308
-- | Pass statement (null operation).
297309
| Pass { stmt_annot :: annot }
298310
-- | Break statement (may only occur syntactically nested in a for or while loop, but not nested in a function or class definition within that loop).
@@ -635,6 +647,8 @@ data Expr annot
635647
}
636648
-- | Generator.
637649
| Generator { gen_comprehension :: Comprehension annot, expr_annot :: annot }
650+
-- | Await
651+
| Await { await_expr :: Expr annot, expr_annot :: annot }
638652
-- | List comprehension.
639653
| ListComp { list_comprehension :: Comprehension annot, expr_annot :: annot }
640654
-- | List.

src/Language/Python/Common/PrettyAST.hs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,12 @@ instance Pretty (Statement a) where
9696
pretty stmt@(For {})
9797
= text "for" <+> commaList (for_targets stmt) <+> text "in" <+> pretty (for_generator stmt) <> colon $+$
9898
indent (prettySuite (for_body stmt)) $+$ optionalKeywordSuite "else" (for_else stmt)
99+
pretty (AsyncFor { for_stmt = fs }) = zeroWidthText "async " <> pretty fs
99100
pretty stmt@(Fun {})
100101
= text "def" <+> pretty (fun_name stmt) <> parens (commaList (fun_args stmt)) <+>
101102
perhaps (fun_result_annotation stmt) (text "->") <+>
102103
pretty (fun_result_annotation stmt) <> colon $+$ indent (prettySuite (fun_body stmt))
104+
pretty (AsyncFun { fun_def = fd }) = text "async" <+> pretty fd
103105
pretty stmt@(Class {})
104106
= text "class" <+> pretty (class_name stmt) <> prettyOptionalList (class_args stmt) <>
105107
colon $+$ indent (prettySuite (class_body stmt))
@@ -127,6 +129,7 @@ instance Pretty (Statement a) where
127129
pretty (With { with_context = context, with_body = body })
128130
= text "with" <+> hcat (punctuate comma (map prettyWithContext context)) <+> colon $+$
129131
indent (prettySuite body)
132+
pretty (AsyncWith { with_stmt = ws }) = text "async" <+> pretty ws
130133
pretty Pass {} = text "pass"
131134
pretty Break {} = text "break"
132135
pretty Continue {} = text "continue"
@@ -250,6 +253,7 @@ instance Pretty (Expr a) where
250253
pretty (Yield { yield_arg = arg })
251254
= text "yield" <+> pretty arg
252255
pretty (Generator { gen_comprehension = gc }) = parens $ pretty gc
256+
pretty (Await { await_expr = ae }) = text "await" <+> pretty ae
253257
pretty (ListComp { list_comprehension = lc }) = brackets $ pretty lc
254258
pretty (List { list_exprs = es }) = brackets (commaList es)
255259
pretty (Dictionary { dict_mappings = mappings })

src/Language/Python/Common/PrettyToken.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ instance Pretty Token where
6565
AsToken {} -> text "as"
6666
ElifToken {} -> text "elif"
6767
YieldToken {} -> text "yield"
68+
AsyncToken {} -> text "async"
69+
AwaitToken {} -> text "await"
6870
AssertToken {} -> text "assert"
6971
ImportToken {} -> text "import"
7072
PassToken {} -> text "pass"

src/Language/Python/Common/Token.hs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ data Token
8686
| OrToken { token_span :: !SrcSpan } -- ^ Keyword: boolean disjunction \'or\'.
8787
-- Version 3.x only:
8888
| NonLocalToken { token_span :: !SrcSpan } -- ^ Keyword: \'nonlocal\' (Python 3.x only)
89+
| AsyncToken { token_span :: !SrcSpan } -- ^ Keyword: \'async\' (Python 3.x only)
90+
| AwaitToken { token_span :: !SrcSpan } -- ^ Keyword: \'await\' (Python 3.x only)
8991
-- Version 2.x only:
9092
| PrintToken { token_span :: !SrcSpan } -- ^ Keyword: \'print\'. (Python 2.x only)
9193
| ExecToken { token_span :: !SrcSpan } -- ^ Keyword: \'exec\'. (Python 2.x only)
@@ -220,6 +222,8 @@ classifyToken token =
220222
AsToken {} -> Keyword
221223
ElifToken {} -> Keyword
222224
YieldToken {} -> Keyword
225+
AsyncToken {} -> Keyword
226+
AwaitToken {} -> Keyword
223227
AssertToken {} -> Keyword
224228
ImportToken {} -> Keyword
225229
PassToken {} -> Keyword
@@ -322,6 +326,8 @@ tokenString token =
322326
AsToken {} -> "as"
323327
ElifToken {} -> "elif"
324328
YieldToken {} -> "yield"
329+
AsyncToken {} -> "async"
330+
AwaitToken {} -> "await"
325331
AssertToken {} -> "assert"
326332
ImportToken {} -> "import"
327333
PassToken {} -> "pass"

src/Language/Python/Version3/Parser/Lexer.x

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,5 +282,6 @@ keywordNames =
282282
, ("as", AsToken), ("elif", ElifToken), ("if", IfToken), ("or", OrToken), ("yield", YieldToken)
283283
, ("assert", AssertToken), ("else", ElseToken), ("import", ImportToken), ("pass", PassToken)
284284
, ("break", BreakToken), ("except", ExceptToken), ("in", InToken), ("raise", RaiseToken)
285+
, ("async", AsyncToken), ("await", AwaitToken)
285286
]
286287
}

src/Language/Python/Version3/Parser/Parser.y

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ import Data.Maybe (maybeToList)
8181
'and' { AndToken {} }
8282
'as' { AsToken {} }
8383
'assert' { AssertToken {} }
84+
'async' { AsyncToken {} }
85+
'await' { AwaitToken {} }
8486
'break' { BreakToken {} }
8587
'bytestring' { ByteStringToken {} }
8688
'class' { ClassToken {} }
@@ -223,8 +225,9 @@ decorators : many1(decorator) { $1 }
223225
224226
decorated :: { StatementSpan }
225227
decorated
226-
: decorators or(classdef,funcdef)
227-
{ makeDecorated $1 $2 }
228+
: decorators classdef { makeDecorated $1 $2 }
229+
| decorators funcdef { makeDecorated $1 $2 }
230+
| decorators async_funcdef { makeDecorated $1 $2 }
228231
229232
-- funcdef: 'def' NAME parameters ['->' test] ':' suite
230233
@@ -515,7 +518,7 @@ assert_stmt :: { StatementSpan }
515518
assert_stmt : 'assert' sepBy(test,',')
516519
{ AST.Assert $2 (spanning $1 $2) }
517520

518-
-- compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated
521+
-- compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated | async_stmt
519522

520523
compound_stmt :: { StatementSpan }
521524
compound_stmt
@@ -527,6 +530,7 @@ compound_stmt
527530
| funcdef { $1 }
528531
| classdef { $1 }
529532
| decorated { $1 }
533+
| async_stmt { $1 }
530534

531535
-- if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
532536

@@ -556,6 +560,20 @@ for_stmt
556560
: 'for' exprlist 'in' testlist ':' suite optional_else
557561
{ AST.For $2 $4 $6 $7 (spanning (spanning $1 $6) $7) }
558562

563+
-- async_stmt: ASYNC (funcdef | with_stmt | for_stmt)
564+
565+
async_stmt :: { StatementSpan }
566+
async_stmt
567+
: 'async' funcdef { AST.AsyncFun $2 (spanning $1 $2) }
568+
| 'async' with_stmt { AST.AsyncWith $2 (spanning $1 $2) }
569+
| 'async' for_stmt { AST.AsyncFor $2 (spanning $1 $2) }
570+
571+
-- async_fundef: ASYNC funcdef
572+
573+
async_funcdef :: { StatementSpan }
574+
async_funcdef
575+
: 'async' funcdef { AST.AsyncFun $2 (spanning $1 $2) }
576+
559577
{-
560578
try_stmt: ('try' ':' suite
561579
((except_clause ':' suite)+ ['else' ':' suite] ['finally' ':' suite] | 'finally' ':' suite))
@@ -754,10 +772,14 @@ factor
754772
tilde_op :: { OpSpan }
755773
tilde_op: '~' { AST.Invert (getSpan $1) }
756774
775+
-- await_expr: 'await' primary
776+
await_expr :: { ExprSpan }
777+
await_expr : 'await' atom { AST.Await $2 (spanning $1 $2) }
778+
757779
-- power: atom trailer* ['**' factor]
758780
759781
power :: { ExprSpan }
760-
power : atom many0(trailer) opt(pair(exponent_op, factor))
782+
power : or(await_expr, atom) many0(trailer) opt(pair(exponent_op, factor))
761783
{ makeBinOp (addTrailer $1 $2) (maybeToList $3) }
762784
763785
exponent_op :: { OpSpan }

0 commit comments

Comments
 (0)