Skip to content

Commit 5bc1aa0

Browse files
committed
Add async def and async for parsing.
1 parent 8f3b62b commit 5bc1aa0

File tree

8 files changed

+112
-13
lines changed

8 files changed

+112
-13
lines changed

parser/src/ast.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,12 @@ pub enum Statement {
9898
body: Vec<LocatedStatement>,
9999
orelse: Option<Vec<LocatedStatement>>,
100100
},
101+
AsyncFor {
102+
target: Expression,
103+
iter: Expression,
104+
body: Vec<LocatedStatement>,
105+
orelse: Option<Vec<LocatedStatement>>,
106+
},
101107
Raise {
102108
exception: Option<Expression>,
103109
cause: Option<Expression>,
@@ -122,6 +128,13 @@ pub enum Statement {
122128
decorator_list: Vec<Expression>,
123129
returns: Option<Expression>,
124130
},
131+
AsyncFunctionDef {
132+
name: String,
133+
args: Parameters,
134+
body: Vec<LocatedStatement>,
135+
decorator_list: Vec<Expression>,
136+
returns: Option<Expression>,
137+
},
125138
}
126139

127140
#[derive(Debug, PartialEq)]

parser/src/lexer.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ pub fn get_keywords() -> HashMap<String, Tok> {
9595
keywords.insert(String::from("and"), Tok::And);
9696
keywords.insert(String::from("as"), Tok::As);
9797
keywords.insert(String::from("assert"), Tok::Assert);
98+
keywords.insert(String::from("async"), Tok::Async);
99+
keywords.insert(String::from("await"), Tok::Await);
98100
keywords.insert(String::from("break"), Tok::Break);
99101
keywords.insert(String::from("class"), Tok::Class);
100102
keywords.insert(String::from("continue"), Tok::Continue);

parser/src/python.lalrpop

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -348,13 +348,14 @@ WhileStatement: ast::LocatedStatement = {
348348
};
349349

350350
ForStatement: ast::LocatedStatement = {
351-
<loc:@L> "for" <e:ExpressionList> "in" <t:TestList> ":" <s:Suite> <s2:("else" ":" Suite)?> => {
352-
let or_else = s2.map(|s| s.2);
351+
<loc:@L> <is_async:"async"?> "for" <target:ExpressionList> "in" <iter:TestList> ":" <body:Suite> <s2:("else" ":" Suite)?> => {
352+
let orelse = s2.map(|s| s.2);
353353
ast::LocatedStatement {
354354
location: loc,
355-
node: ast::Statement::For {
356-
target: e,
357-
iter: t, body: s, orelse: or_else
355+
node: if is_async.is_some() {
356+
ast::Statement::AsyncFor { target, iter, body, orelse }
357+
} else {
358+
ast::Statement::For { target, iter, body, orelse }
358359
},
359360
}
360361
},
@@ -410,16 +411,26 @@ WithItem: ast::WithItem = {
410411
};
411412

412413
FuncDef: ast::LocatedStatement = {
413-
<d:Decorator*> <loc:@L> "def" <i:Identifier> <a:Parameters> <r:("->" Test)?> ":" <s:Suite> => {
414+
<d:Decorator*> <loc:@L> <is_async:"async"?> "def" <i:Identifier> <a:Parameters> <r:("->" Test)?> ":" <s:Suite> => {
414415
ast::LocatedStatement {
415416
location: loc,
416-
node: ast::Statement::FunctionDef {
417-
name: i,
418-
args: a,
419-
body: s,
420-
decorator_list: d,
421-
returns: r.map(|x| x.1),
422-
}
417+
node: if is_async.is_some() {
418+
ast::Statement::AsyncFunctionDef {
419+
name: i,
420+
args: a,
421+
body: s,
422+
decorator_list: d,
423+
returns: r.map(|x| x.1),
424+
}
425+
} else {
426+
ast::Statement::FunctionDef {
427+
name: i,
428+
args: a,
429+
body: s,
430+
decorator_list: d,
431+
returns: r.map(|x| x.1),
432+
}
433+
}
423434
}
424435
},
425436
};
@@ -1045,6 +1056,8 @@ extern {
10451056
"and" => lexer::Tok::And,
10461057
"as" => lexer::Tok::As,
10471058
"assert" => lexer::Tok::Assert,
1059+
"async" => lexer::Tok::Async,
1060+
"await" => lexer::Tok::Await,
10481061
"break" => lexer::Tok::Break,
10491062
"class" => lexer::Tok::Class,
10501063
"continue" => lexer::Tok::Continue,

parser/src/token.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ pub enum Tok {
7272
And,
7373
As,
7474
Assert,
75+
Async,
76+
Await,
7577
Break,
7678
Class,
7779
Continue,

tests/snippets/test_async_stuff.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
import sys
3+
import ast
4+
5+
src = """
6+
async def x():
7+
async for x in [1,2,3]:
8+
pass
9+
"""
10+
11+
mod = ast.parse(src)
12+
# print(mod)
13+
# print(ast.dump(mod))

vm/src/compile.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,9 @@ impl Compiler {
322322
body,
323323
orelse,
324324
} => self.compile_for(target, iter, body, orelse)?,
325+
ast::Statement::AsyncFor { .. } => {
326+
unimplemented!("async for");
327+
}
325328
ast::Statement::Raise { exception, cause } => match exception {
326329
Some(value) => {
327330
self.compile_expression(value)?;
@@ -352,6 +355,9 @@ impl Compiler {
352355
decorator_list,
353356
returns,
354357
} => self.compile_function_def(name, args, body, decorator_list, returns)?,
358+
ast::Statement::AsyncFunctionDef { .. } => {
359+
unimplemented!("async def");
360+
}
355361
ast::Statement::ClassDef {
356362
name,
357363
body,

vm/src/stdlib/ast.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,26 @@ fn statement_to_ast(
9696
returns => py_returns
9797
})
9898
}
99+
ast::Statement::AsyncFunctionDef {
100+
name,
101+
args,
102+
body,
103+
decorator_list,
104+
returns,
105+
} => {
106+
let py_returns = if let Some(hint) = returns {
107+
expression_to_ast(vm, hint)?.into_object()
108+
} else {
109+
vm.ctx.none()
110+
};
111+
node!(vm, AsyncFunctionDef, {
112+
name => vm.ctx.new_str(name.to_string()),
113+
args => parameters_to_ast(vm, args)?,
114+
body => statements_to_ast(vm, body)?,
115+
decorator_list => expressions_to_ast(vm, decorator_list)?,
116+
returns => py_returns
117+
})
118+
}
99119
ast::Statement::Continue => node!(vm, Continue),
100120
ast::Statement::Break => node!(vm, Break),
101121
ast::Statement::Pass => node!(vm, Pass),
@@ -152,6 +172,21 @@ fn statement_to_ast(
152172
vm.ctx.none()
153173
}
154174
}),
175+
ast::Statement::AsyncFor {
176+
target,
177+
iter,
178+
body,
179+
orelse,
180+
} => node!(vm, AsyncFor, {
181+
target => expression_to_ast(vm, target)?,
182+
iter => expression_to_ast(vm, iter)?,
183+
body => statements_to_ast(vm, body)?,
184+
or_else => if let Some(orelse) = orelse {
185+
statements_to_ast(vm, orelse)?.into_object()
186+
} else {
187+
vm.ctx.none()
188+
}
189+
}),
155190
ast::Statement::While { test, body, orelse } => node!(vm, While, {
156191
test => expression_to_ast(vm, test)?,
157192
body => statements_to_ast(vm, body)?,
@@ -462,6 +497,8 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
462497
// TODO: There's got to be a better way!
463498
"arg" => py_class!(ctx, "_ast.arg", ast_base.clone(), {}),
464499
"arguments" => py_class!(ctx, "_ast.arguments", ast_base.clone(), {}),
500+
"AsyncFor" => py_class!(ctx, "_ast.AsyncFor", ast_base.clone(), {}),
501+
"AsyncFunctionDef" => py_class!(ctx, "_ast.AsyncFunctionDef", ast_base.clone(), {}),
465502
"Assert" => py_class!(ctx, "_ast.Assert", ast_base.clone(), {}),
466503
"Attribute" => py_class!(ctx, "_ast.Attribute", ast_base.clone(), {}),
467504
"BinOp" => py_class!(ctx, "_ast.BinOp", ast_base.clone(), {}),

vm/src/symboltable.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,13 @@ impl SymbolTableBuilder {
223223
args,
224224
decorator_list,
225225
returns,
226+
}
227+
| ast::Statement::AsyncFunctionDef {
228+
name,
229+
body,
230+
args,
231+
decorator_list,
232+
returns,
226233
} => {
227234
self.scan_expressions(decorator_list)?;
228235
self.register_name(name, SymbolRole::Assigned)?;
@@ -265,6 +272,12 @@ impl SymbolTableBuilder {
265272
iter,
266273
body,
267274
orelse,
275+
}
276+
| ast::Statement::AsyncFor {
277+
target,
278+
iter,
279+
body,
280+
orelse,
268281
} => {
269282
self.scan_expression(target)?;
270283
self.scan_expression(iter)?;

0 commit comments

Comments
 (0)