mirror of
https://github.com/RustPython/Parser.git
synced 2025-07-18 18:45:23 +00:00
compile_with as recursive form
This commit is contained in:
parent
a9306971ae
commit
fa6c66272e
2 changed files with 56 additions and 38 deletions
|
@ -1395,57 +1395,67 @@ impl Compiler {
|
||||||
) -> CompileResult<()> {
|
) -> CompileResult<()> {
|
||||||
let with_location = self.current_source_location;
|
let with_location = self.current_source_location;
|
||||||
|
|
||||||
let end_blocks = items
|
let (item, items) = if let Some(parts) = items.split_first() {
|
||||||
.iter()
|
parts
|
||||||
.map(|item| {
|
} else {
|
||||||
let end_block = self.new_block();
|
return Err(self.error(CompileErrorType::EmptyWithItems));
|
||||||
self.compile_expression(&item.context_expr)?;
|
};
|
||||||
|
|
||||||
self.set_source_location(with_location);
|
let final_block = {
|
||||||
if is_async {
|
let final_block = self.new_block();
|
||||||
self.emit(Instruction::BeforeAsyncWith);
|
self.compile_expression(&item.context_expr)?;
|
||||||
self.emit(Instruction::GetAwaitable);
|
|
||||||
self.emit_constant(ConstantData::None);
|
self.set_source_location(with_location);
|
||||||
self.emit(Instruction::YieldFrom);
|
if is_async {
|
||||||
self.emit(Instruction::SetupAsyncWith { end: end_block });
|
self.emit(Instruction::BeforeAsyncWith);
|
||||||
} else {
|
self.emit(Instruction::GetAwaitable);
|
||||||
self.emit(Instruction::SetupWith { end: end_block });
|
self.emit_constant(ConstantData::None);
|
||||||
|
self.emit(Instruction::YieldFrom);
|
||||||
|
self.emit(Instruction::SetupAsyncWith { end: final_block });
|
||||||
|
} else {
|
||||||
|
self.emit(Instruction::SetupWith { end: final_block });
|
||||||
|
}
|
||||||
|
|
||||||
|
match &item.optional_vars {
|
||||||
|
Some(var) => {
|
||||||
|
self.set_source_location(var.location);
|
||||||
|
self.compile_store(var)?;
|
||||||
}
|
}
|
||||||
|
None => {
|
||||||
match &item.optional_vars {
|
self.emit(Instruction::Pop);
|
||||||
Some(var) => {
|
|
||||||
self.set_source_location(var.location);
|
|
||||||
self.compile_store(var)?;
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
self.emit(Instruction::Pop);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(end_block)
|
}
|
||||||
})
|
final_block
|
||||||
.collect::<CompileResult<Vec<_>>>()?;
|
};
|
||||||
|
|
||||||
self.compile_statements(body)?;
|
if items.is_empty() {
|
||||||
|
if body.is_empty() {
|
||||||
|
return Err(self.error(CompileErrorType::EmptyWithBody));
|
||||||
|
}
|
||||||
|
self.compile_statements(body)?;
|
||||||
|
} else {
|
||||||
|
self.set_source_location(with_location);
|
||||||
|
self.compile_with(items, body, is_async)?;
|
||||||
|
}
|
||||||
|
|
||||||
// sort of "stack up" the layers of with blocks:
|
// sort of "stack up" the layers of with blocks:
|
||||||
// with a, b: body -> start_with(a) start_with(b) body() end_with(b) end_with(a)
|
// with a, b: body -> start_with(a) start_with(b) body() end_with(b) end_with(a)
|
||||||
self.set_source_location(with_location);
|
self.set_source_location(with_location);
|
||||||
for end_block in end_blocks.into_iter().rev() {
|
self.emit(Instruction::PopBlock);
|
||||||
self.emit(Instruction::PopBlock);
|
|
||||||
self.emit(Instruction::EnterFinally);
|
|
||||||
|
|
||||||
self.switch_to_block(end_block);
|
self.emit(Instruction::EnterFinally);
|
||||||
self.emit(Instruction::WithCleanupStart);
|
|
||||||
|
|
||||||
if is_async {
|
self.switch_to_block(final_block);
|
||||||
self.emit(Instruction::GetAwaitable);
|
self.emit(Instruction::WithCleanupStart);
|
||||||
self.emit_constant(ConstantData::None);
|
|
||||||
self.emit(Instruction::YieldFrom);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.emit(Instruction::WithCleanupFinish);
|
if is_async {
|
||||||
|
self.emit(Instruction::GetAwaitable);
|
||||||
|
self.emit_constant(ConstantData::None);
|
||||||
|
self.emit(Instruction::YieldFrom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.emit(Instruction::WithCleanupFinish);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,8 @@ pub enum CompileErrorType {
|
||||||
InvalidFutureFeature(String),
|
InvalidFutureFeature(String),
|
||||||
FunctionImportStar,
|
FunctionImportStar,
|
||||||
TooManyStarUnpack,
|
TooManyStarUnpack,
|
||||||
|
EmptyWithItems,
|
||||||
|
EmptyWithBody,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for CompileErrorType {
|
impl fmt::Display for CompileErrorType {
|
||||||
|
@ -70,6 +72,12 @@ impl fmt::Display for CompileErrorType {
|
||||||
CompileErrorType::TooManyStarUnpack => {
|
CompileErrorType::TooManyStarUnpack => {
|
||||||
write!(f, "too many expressions in star-unpacking assignment")
|
write!(f, "too many expressions in star-unpacking assignment")
|
||||||
}
|
}
|
||||||
|
CompileErrorType::EmptyWithItems => {
|
||||||
|
write!(f, "empty items on With")
|
||||||
|
}
|
||||||
|
CompileErrorType::EmptyWithBody => {
|
||||||
|
write!(f, "empty body on With")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue