Skip to content

Commit 78d80db

Browse files
committed
implement async for function in compiler
1 parent 2dade29 commit 78d80db

File tree

3 files changed

+50
-23
lines changed

3 files changed

+50
-23
lines changed

bytecode/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1061,7 +1061,7 @@ impl Instruction {
10611061
}
10621062
GetAIter => 0,
10631063
GetANext => 1,
1064-
EndAsyncFor => -2,
1064+
EndAsyncFor => -1,
10651065
}
10661066
}
10671067

compiler/src/compile.rs

Lines changed: 49 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ enum CallType {
3333
Keyword { nargs: u32 },
3434
Ex { has_kwargs: bool },
3535
}
36+
3637
impl CallType {
3738
fn normal_call(self) -> Instruction {
3839
match self {
@@ -69,6 +70,7 @@ pub struct CompileOpts {
6970
/// not emit assert statements
7071
pub optimize: u8,
7172
}
73+
7274
impl Default for CompileOpts {
7375
fn default() -> Self {
7476
CompileOpts { optimize: 0 }
@@ -1608,7 +1610,7 @@ impl Compiler {
16081610
"starred assignment target must be in a list or tuple".to_owned(),
16091611
),
16101612
_ => CompileErrorType::Assign(target.node.name()),
1611-
}))
1613+
}));
16121614
}
16131615
}
16141616

@@ -1907,10 +1909,10 @@ impl Compiler {
19071909
YieldFrom { value } => {
19081910
match self.ctx.func {
19091911
FunctionContext::NoFunction => {
1910-
return Err(self.error(CompileErrorType::InvalidYieldFrom))
1912+
return Err(self.error(CompileErrorType::InvalidYieldFrom));
19111913
}
19121914
FunctionContext::AsyncFunction => {
1913-
return Err(self.error(CompileErrorType::AsyncYieldFrom))
1915+
return Err(self.error(CompileErrorType::AsyncYieldFrom));
19141916
}
19151917
FunctionContext::Function => {}
19161918
}
@@ -2295,37 +2297,48 @@ impl Compiler {
22952297
}
22962298

22972299
let mut loop_labels = vec![];
2300+
let mut is_async = false;
22982301
for generator in generators {
2299-
if generator.is_async {
2300-
unimplemented!("async for comprehensions");
2301-
}
2302-
23032302
let loop_block = self.new_block();
23042303
let after_block = self.new_block();
23052304

23062305
// Setup for loop:
2307-
self.emit(Instruction::SetupLoop {
2308-
break_target: after_block,
2309-
});
2306+
if !generator.is_async {
2307+
self.emit(Instruction::SetupLoop {
2308+
break_target: after_block,
2309+
});
2310+
}
23102311

23112312
if loop_labels.is_empty() {
23122313
// Load iterator onto stack (passed as first argument):
23132314
self.emit(Instruction::LoadFast(arg0));
23142315
} else {
23152316
// Evaluate iterated item:
23162317
self.compile_expression(&generator.iter)?;
2317-
2318-
// Get iterator / turn item into an iterator
2319-
self.emit(Instruction::GetIter);
2318+
if generator.is_async {
2319+
self.emit(Instruction::GetAIter);
2320+
} else {
2321+
// Get iterator / turn item into an iterator
2322+
self.emit(Instruction::GetIter);
2323+
}
23202324
}
23212325

23222326
loop_labels.push((loop_block, after_block));
2323-
23242327
self.switch_to_block(loop_block);
2325-
self.emit(Instruction::ForIter {
2326-
target: after_block,
2327-
});
2328-
2328+
if generator.is_async {
2329+
is_async = true;
2330+
self.emit(Instruction::SetupFinally {
2331+
handler: after_block,
2332+
});
2333+
self.emit(Instruction::GetANext);
2334+
self.emit_constant(ConstantData::None);
2335+
self.emit(Instruction::YieldFrom);
2336+
self.emit(Instruction::PopBlock);
2337+
} else {
2338+
self.emit(Instruction::ForIter {
2339+
target: after_block,
2340+
});
2341+
}
23292342
self.compile_store(&generator.target)?;
23302343

23312344
// Now evaluate the ifs:
@@ -2342,7 +2355,11 @@ impl Compiler {
23422355

23432356
// End of for loop:
23442357
self.switch_to_block(after_block);
2345-
self.emit(Instruction::PopBlock);
2358+
if is_async {
2359+
self.emit(Instruction::EndAsyncFor);
2360+
} else {
2361+
self.emit(Instruction::PopBlock);
2362+
}
23462363
}
23472364

23482365
if return_none {
@@ -2379,10 +2396,19 @@ impl Compiler {
23792396
self.compile_expression(&generators[0].iter)?;
23802397

23812398
// Get iterator / turn item into an iterator
2382-
self.emit(Instruction::GetIter);
2399+
if is_async {
2400+
self.emit(Instruction::GetAIter);
2401+
} else {
2402+
self.emit(Instruction::GetIter);
2403+
}
23832404

23842405
// Call just created <listcomp> function:
23852406
self.emit(Instruction::CallFunctionPositional { nargs: 1 });
2407+
if is_async {
2408+
self.emit(Instruction::GetAwaitable);
2409+
self.emit_constant(ConstantData::None);
2410+
self.emit(Instruction::YieldFrom);
2411+
}
23862412
Ok(())
23872413
}
23882414

@@ -2398,7 +2424,9 @@ impl Compiler {
23982424
// "generator_stop" => {}
23992425
// "annotations" => {}
24002426
other => {
2401-
return Err(self.error(CompileErrorType::InvalidFutureFeature(other.to_owned())))
2427+
return Err(
2428+
self.error(CompileErrorType::InvalidFutureFeature(other.to_owned()))
2429+
);
24022430
}
24032431
}
24042432
}

vm/src/frame.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -902,7 +902,6 @@ impl ExecutingFrame<'_> {
902902
}
903903
bytecode::Instruction::EndAsyncFor => {
904904
let exc = self.pop_value();
905-
self.pop_value(); // async iterator we were calling __anext__ on
906905
if exc.isinstance(&vm.ctx.exceptions.stop_async_iteration) {
907906
vm.take_exception().expect("Should have exception in stack");
908907
Ok(None)

0 commit comments

Comments
 (0)