Add async with, reorganize how with blocks work

This commit is contained in:
coolreader18 2019-10-16 22:28:49 -05:00
parent 3638591cde
commit ae825125a5

View file

@ -386,10 +386,49 @@ impl<O: OutputStream> Compiler<O> {
body, body,
} => { } => {
if *is_async { if *is_async {
unimplemented!("async with"); let end_labels = items
} else { .iter()
.map(|item| {
let end_label = self.new_label();
self.compile_expression(&item.context_expr)?;
self.emit(Instruction::BeforeAsyncWith);
self.emit(Instruction::GetAwaitable);
self.emit(Instruction::LoadConst {
value: bytecode::Constant::None,
});
self.emit(Instruction::YieldFrom);
self.emit(Instruction::SetupAsyncWith { end: end_label });
match &item.optional_vars {
Some(var) => {
self.compile_store(var)?;
}
None => {
self.emit(Instruction::Pop);
}
}
Ok(end_label)
})
.collect::<Result<Vec<_>, CompileError>>()?;
self.compile_statements(body)?;
for end_label in end_labels {
self.emit(Instruction::PopBlock);
self.emit(Instruction::EnterFinally);
self.set_label(end_label);
self.emit(Instruction::WithCleanupStart);
self.emit(Instruction::GetAwaitable);
self.emit(Instruction::LoadConst {
value: bytecode::Constant::None,
});
self.emit(Instruction::YieldFrom);
self.emit(Instruction::WithCleanupFinish);
}
} else {
let end_labels = items
.iter()
.map(|item| {
let end_label = self.new_label(); let end_label = self.new_label();
for item in items {
self.compile_expression(&item.context_expr)?; self.compile_expression(&item.context_expr)?;
self.emit(Instruction::SetupWith { end: end_label }); self.emit(Instruction::SetupWith { end: end_label });
match &item.optional_vars { match &item.optional_vars {
@ -400,13 +439,19 @@ impl<O: OutputStream> Compiler<O> {
self.emit(Instruction::Pop); self.emit(Instruction::Pop);
} }
} }
} Ok(end_label)
})
.collect::<Result<Vec<_>, CompileError>>()?;
self.compile_statements(body)?; self.compile_statements(body)?;
for _ in 0..items.len() {
self.emit(Instruction::CleanupWith { end: end_label }); for end_label in end_labels {
} self.emit(Instruction::PopBlock);
self.emit(Instruction::EnterFinally);
self.set_label(end_label); self.set_label(end_label);
self.emit(Instruction::WithCleanupStart);
self.emit(Instruction::WithCleanupFinish);
}
} }
} }
For { For {