8000 Handle try…except in a try…except. · tempbottle/pythonvm-rust@3c3d329 · GitHub
[go: up one dir, main page]

Skip to content

Commit 3c3d329

Browse files
committed
Handle try…except in a try…except.
1 parent fba782d commit 3c3d329

File tree

2 files changed

+57
-35
lines changed

2 files changed

+57
-35
lines changed

functional_tests/catch_exceptions.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,15 @@ class Bar(BaseException):
5151
print('not raised')
5252

5353
print('----')
54+
55+
try:
56+
try:
57+
raise Bar()
58+
except Foo:
59+
print('raised Foo')
60+
except Bar:
61+
print('raised Bar')
62+
else:
63+
print('not raised')
64+
65+
print('----')

src/processor/mod.rs

Lines changed: 45 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -80,41 +80,38 @@ macro_rules! pop_stack {
8080
}
8181
}
8282

83-
macro_rules! unwind {
84-
($call_stack: expr, $traceback: expr, $exception: expr, $exc_type: expr, $value: expr) => {{
85-
// Unwind call stack
86-
'outer: loop {
87-
match $call_stack.pop() {
88-
None => panic!("Exception reached bottom of call stack."),
89-
Some(mut frame) => {
90-
// Unwind block stack
91-
while let Some(block) = frame.block_stack.pop() {
92-
match block {
93-
Block::TryExcept(begin, end) => {
94-
// Found a try…except block
95-
frame.block_stack.push(Block::TryExcept(begin, end)); // Push it back, it will be poped by PopExcept.
96-
frame.program_counter = end;
97-
let traceback = $traceback;
98-
let exception = $exception;
99-
frame.var_stack.push(traceback.clone()); // traceback
100-
frame.var_stack.push(exception.clone()); // exception
101-
frame.var_stack.push($exc_type); // exception type
83+
/// Unwind call stack until a try…except is found.
84+
fn unwind(call_stack: &mut Vec<Frame>, traceback: ObjectRef, exception: ObjectRef, value: ObjectRef) {
85+
let exc_type = exception.clone(); // Looks like that's how CPython does things…
86+
'outer: loop {
87+
match call_stack.pop() {
88+
None => panic!("Exception reached bottom of call stack."),
89+
Some(mut frame) => {
90+
// Unwind block stack
91+
while let Some(block) = frame.block_stack.pop() {
92+
match block {
93+
Block::TryExcept(begin, end) => {
94+
// Found a try…except block
95+
frame.block_stack.push(Block::TryExcept(begin, end)); // Push it back, it will be poped by PopExcept.
96+
frame.program_counter = end;
97+
frame.var_stack.push(traceback.clone());
98+
frame.var_stack.push(value.clone());
99+
frame.var_stack.push(exc_type);
102100

103-
frame.var_stack.push(traceback); // traceback
104-
frame.var_stack.push($value); // value
105-
frame.var_stack.push(exception); // exception
101+
frame.var_stack.push(traceback);
102+
frame.var_stack.push(value);
103+
frame.var_stack.push(exception);
106104

107-
$call_stack.push(frame);
108-
break 'outer
109-
}
110-
_ => { // Non-try…except block, exit it.
111-
}
105+
call_stack.push(frame);
106+
break 'outer
107+
}
108+
_ => { // Non-try…except block, exit it.
112109
}
113110
}
114111
}
115112
}
116113
}
117-
}}
114+
}
118115
}
119116

120117
pub struct Processor<EP: EnvProxy> {
@@ -237,7 +234,7 @@ impl<EP: EnvProxy> Processor<EP> {
237234
let res = function(self, args); // Call the primitive
238235
match res {
239236
PyResult::Return(res) => call_stack.last_mut().unwrap().var_stack.push(res),
240-
PyResult::Raise(exc, exc_type) => unwind!(call_stack, self.primitive_objects.none.clone(), exc, exc_type, self.primitive_objects.none.clone()),
237+
PyResult::Raise(exc, value) => unwind(call_stack, self.primitive_objects.none.clone(), exc, value),
241238
PyResult::Error(err) => self.raise_runtime_error(err),
242239
};
243240
}
@@ -306,13 +303,27 @@ impl<EP: EnvProxy> Processor<EP> {
306303
pop_stack!(frame.block_stack);
307304
}
308305
Instruction::EndFinally => {
309-
let frame = call_stack.last_mut().unwrap();
310-
let status_ref = pop_stack!(frame.var_stack);
306+
let status_ref = {
307+
let frame = call_stack.last_mut().unwrap();
308+
pop_stack!(frame.var_stack)
309+
};
311310
let status = self.store.deref(&status_ref);
312311
match status.content {
313312
ObjectContent::Int(i) => panic!("TODO: finally int status"), // TODO
314-
ObjectContent::OtherObject => {}
315-
_ => panic!("Invalid finally status")
313+
ObjectContent::OtherObject => {
314+
let (val, traceback) = {
315+
let frame = call_stack.last_mut().unwrap();
316+
let val = pop_stack!(frame.var_stack); // Note: CPython calls this variable “exc”
317+
let traceback = pop_stack!(frame.var_stack);
318+
(val, traceback)
319+
};
320+
let exc = status_ref;
321+
call_stack.last_mut().unwrap().block_stack.pop().unwrap(); // Remove this try…except block
322+
unwind(call_stack, traceback, exc, val);
323+
}
324+
ObjectContent::None => {
325+
}
326+
_ => panic!(format!("Invalid finally status: {:?}", status))
316327
}
317328
}
318329
Instruction::PopExcept => {
@@ -402,8 +413,7 @@ impl<EP: EnvProxy> Processor<EP> {
402413
}
403414
Instruction::RaiseVarargs(1) => {
404415
let exception = pop_stack!(call_stack.last_mut().unwrap().var_stack);
405-
let exc_type = exception.clone();
406-
unwind!(call_stack, self.primitive_objects.none.clone(), exception, exc_type, self.primitive_objects.none.clone());
416+
unwind(call_stack, self.primitive_objects.none.clone(), exception, self.primitive_objects.none.clone());
407417
}
408418
Instruction::RaiseVarargs(2) => {
409419
panic!("RaiseVarargs(2) not implemented.")

0 commit comments

Comments
 (0)
0