Skip to content

Commit 9bf1cb3

Browse files
committed
First simple variant of with-statement operational.
1 parent 0f148e1 commit 9bf1cb3

File tree

4 files changed

+58
-8
lines changed

4 files changed

+58
-8
lines changed

vm/src/bytecode.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,9 @@ pub enum Instruction {
121121
SetupWith {
122122
end: Label,
123123
},
124+
CleanupWith {
125+
end: Label,
126+
},
124127
PopBlock,
125128
Raise {
126129
argc: usize,

vm/src/compile.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,19 +200,24 @@ impl Compiler {
200200
self.set_label(end_label);
201201
}
202202
ast::Statement::With { items, body } => {
203+
let end_label = self.new_label();
203204
for item in items {
204205
self.compile_expression(&item.context_expr);
206+
self.emit(Instruction::SetupWith { end: end_label });
205207
match &item.optional_vars {
206208
Some(var) => {
207-
},
209+
self.compile_store(var);
210+
}
208211
None => {
209212
self.emit(Instruction::Pop);
210213
}
211214
}
212215
}
213-
let end_label = self.new_label();
214-
self.emit(Instruction::SetupWith { end: end_label });
216+
215217
self.compile_statements(body);
218+
for _ in 0..items.len() {
219+
self.emit(Instruction::CleanupWith { end: end_label });
220+
}
216221
self.set_label(end_label);
217222
}
218223
ast::Statement::For {

vm/src/frame.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ pub enum Block {
1616
#[allow(dead_code)]
1717
// TODO: Implement try/except blocks
1818
TryExcept { handler: bytecode::Label },
19-
With { end: bytecode::Label },
19+
With {
20+
end: bytecode::Label,
21+
context_manager: PyObjectRef,
22+
},
2023
}
2124

2225
pub struct Frame {

vm/src/vm.rs

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ impl VirtualMachine {
177177

178178
fn with_exit(&mut self) {
179179
// Assume top of stack is __exit__ method:
180+
// TODO: do we want to put the exit call on the stack?
180181
let exit_method = self.pop_value();
181182
let args = PyFuncArgs {
182183
args: vec![],
@@ -192,7 +193,9 @@ impl VirtualMachine {
192193
match block {
193194
Some(Block::Loop { start: _, end: __ }) => break block.unwrap(),
194195
Some(Block::TryExcept { .. }) => {}
195-
Some(Block::With { .. }) => { self.with_exit(); }
196+
Some(Block::With { .. }) => {
197+
self.with_exit();
198+
}
196199
None => panic!("No block to break / continue"),
197200
}
198201
}
@@ -208,7 +211,9 @@ impl VirtualMachine {
208211
self.jump(&handler);
209212
return None;
210213
}
211-
Some(Block::With { .. }) => { self.with_exit(); }
214+
Some(Block::With { .. }) => {
215+
self.with_exit();
216+
}
212217
Some(Block::Loop { .. }) => {}
213218
None => break,
214219
}
@@ -837,8 +842,42 @@ impl VirtualMachine {
837842
None
838843
}
839844
bytecode::Instruction::SetupWith { end } => {
840-
self.push_block(Block::With { end: *end });
841-
None
845+
let obj = self.pop_value();
846+
// Call enter:
847+
match self.call_method(obj, "__enter__", vec![]) {
848+
Ok(manager) => {
849+
self.push_block(Block::With {
850+
end: *end,
851+
context_manager: manager.clone(),
852+
});
853+
self.push_value(manager);
854+
None
855+
}
856+
Err(err) => Some(Err(err)),
857+
}
858+
}
859+
bytecode::Instruction::CleanupWith { end: end1 } => {
860+
let block = self.pop_block().unwrap();
861+
if let Block::With {
862+
end: end2,
863+
context_manager,
864+
} = &block
865+
{
866+
assert!(end1 == end2);
867+
868+
// call exit now:
869+
let exc_type = self.ctx.none();
870+
let exc_val = self.ctx.none();
871+
let exc_tb = self.ctx.none();
872+
self.call_method(
873+
context_manager.clone(),
874+
"__exit__",
875+
vec![exc_type, exc_val, exc_tb],
876+
).unwrap();
877+
None
878+
} else {
879+
panic!("Block stack is incorrect, expected a with block");
880+
}
842881
}
843882
bytecode::Instruction::PopBlock => {
844883
self.pop_block();

0 commit comments

Comments
 (0)