compile_with as recursive form

This commit is contained in:
Jeong YunWon 2022-08-11 03:39:50 +09:00
parent a9306971ae
commit fa6c66272e
2 changed files with 56 additions and 38 deletions

View file

@ -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(())
} }

View file

@ -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")
}
} }
} }
} }