Skip to content

Commit 3b5cc1a

Browse files
committed
more doc comments, split with_exit() method for context manager __exit__ into two methods
1 parent b6edd19 commit 3b5cc1a

5 files changed

Lines changed: 45 additions & 40 deletions

File tree

vm/src/bytecode.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use std::fmt;
1717
#[derive(Clone, PartialEq, Serialize, Deserialize)]
1818
pub struct CodeObject {
1919
pub instructions: Vec<Instruction>,
20+
/// Jump targets.
2021
pub label_map: HashMap<Label, usize>,
2122
pub locations: Vec<ast::Location>,
2223
pub arg_names: Vec<String>, // Names of positional arguments

vm/src/frame.rs

Lines changed: 40 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ pub enum ExecutionResult {
243243
Yield(PyObjectRef),
244244
}
245245

246-
// A valid execution result, or an exception
246+
/// A valid execution result, or an exception
247247
pub type FrameResult = Result<Option<ExecutionResult>, PyObjectRef>;
248248

249249
impl Frame {
@@ -285,9 +285,11 @@ impl Frame {
285285
Ok(Some(value)) => {
286286
break Ok(value);
287287
}
288+
// Instruction raised an exception
288289
Err(exception) => {
289-
// unwind block stack on exception and find any handlers.
290-
// Add an entry in the traceback:
290+
// 1. Extract traceback from exception's '__traceback__' attr.
291+
// 2. Add new entry with current execution position (filename, lineno, code_object) to traceback.
292+
// 3. Unwind block stack till appropriate handler is found.
291293
assert!(objtype::isinstance(
292294
&exception,
293295
&vm.ctx.exceptions.base_exception_type
@@ -296,13 +298,12 @@ impl Frame {
296298
.get_attribute(exception.clone(), "__traceback__")
297299
.unwrap();
298300
trace!("Adding to traceback: {:?} {:?}", traceback, lineno);
299-
let pos = vm.ctx.new_tuple(vec![
301+
let raise_location = vm.ctx.new_tuple(vec![
300302
vm.ctx.new_str(filename.clone()),
301303
vm.ctx.new_int(lineno.get_row()),
302304
vm.ctx.new_str(run_obj_name.clone()),
303305
]);
304-
objlist::PyListRef::try_from_object(vm, traceback)?.append(pos, vm);
305-
// exception.__trace
306+
objlist::PyListRef::try_from_object(vm, traceback)?.append(raise_location, vm);
306307
match self.unwind_exception(vm, exception) {
307308
None => {}
308309
Some(exception) => {
@@ -333,7 +334,7 @@ impl Frame {
333334
ins2
334335
}
335336

336-
// Execute a single instruction:
337+
/// Execute a single instruction.
337338
fn execute_instruction(&self, vm: &VirtualMachine) -> FrameResult {
338339
let instruction = self.fetch_instruction();
339340
{
@@ -565,9 +566,7 @@ impl Frame {
565566
} = &block.typ
566567
{
567568
debug_assert!(end1 == end2);
568-
569-
// call exit now with no exception:
570-
self.with_exit(vm, &context_manager, None)?;
569+
self.call_context_manager_exit_no_exception(vm, &context_manager)?;
571570
} else {
572571
unreachable!("Block stack is incorrect, expected a with block");
573572
}
@@ -949,7 +948,7 @@ impl Frame {
949948
BlockType::With {
950949
context_manager, ..
951950
} => {
952-
match self.with_exit(vm, &context_manager, None) {
951+
match self.call_context_manager_exit_no_exception(vm, &context_manager) {
953952
Ok(..) => {}
954953
Err(exc) => {
955954
// __exit__ went wrong,
@@ -976,7 +975,7 @@ impl Frame {
976975
}
977976
BlockType::With {
978977
context_manager, ..
979-
} => match self.with_exit(vm, &context_manager, None) {
978+
} => match self.call_context_manager_exit_no_exception(vm, &context_manager) {
980979
Ok(..) => {}
981980
Err(exc) => {
982981
panic!("Exception in with __exit__ {:?}", exc);
@@ -1006,12 +1005,12 @@ impl Frame {
10061005
end,
10071006
context_manager,
10081007
} => {
1009-
match self.with_exit(vm, &context_manager, Some(exc.clone())) {
1010-
Ok(exit_action) => {
1011-
match objbool::boolval(vm, exit_action) {
1012-
Ok(handle_exception) => {
1013-
if handle_exception {
1014-
// We handle the exception, so return!
1008+
match self.call_context_manager_exit(vm, &context_manager, exc.clone()) {
1009+
Ok(exit_result_obj) => {
1010+
match objbool::boolval(vm, exit_result_obj) {
1011+
// If __exit__ method returned True, suppress the exception and continue execution.
1012+
Ok(suppress_exception) => {
1013+
if suppress_exception {
10151014
self.jump(end);
10161015
return None;
10171016
} else {
@@ -1022,7 +1021,6 @@ impl Frame {
10221021
return Some(exit_exc);
10231022
}
10241023
}
1025-
// if objtype::isinstance
10261024
}
10271025
Err(exit_exc) => {
10281026
// TODO: what about original exception?
@@ -1031,36 +1029,39 @@ impl Frame {
10311029
}
10321030
}
10331031
BlockType::Loop { .. } => {}
1034-
// Exception was already poped on Raised.
1032+
// Exception was already popped on Raised.
10351033
BlockType::ExceptHandler => {}
10361034
}
10371035
}
10381036
Some(exc)
10391037
}
10401038

1041-
fn with_exit(
1039+
fn call_context_manager_exit_no_exception(
10421040
&self,
10431041
vm: &VirtualMachine,
10441042
context_manager: &PyObjectRef,
1045-
exc: Option<PyObjectRef>,
10461043
) -> PyResult {
1047-
// Assume top of stack is __exit__ method:
10481044
// TODO: do we want to put the exit call on the stack?
1049-
// let exit_method = self.pop_value();
1050-
// let args = PyFuncArgs::default();
1051-
// TODO: what happens when we got an error during handling exception?
1052-
let args = if let Some(exc) = exc {
1053-
let exc_type = exc.class().into_object();
1054-
let exc_val = exc.clone();
1055-
let exc_tb = vm.ctx.none(); // TODO: retrieve traceback?
1056-
vec![exc_type, exc_val, exc_tb]
1057-
} else {
1058-
let exc_type = vm.ctx.none();
1059-
let exc_val = vm.ctx.none();
1060-
let exc_tb = vm.ctx.none();
1061-
vec![exc_type, exc_val, exc_tb]
1062-
};
1063-
vm.call_method(context_manager, "__exit__", args)
1045+
// TODO: what happens when we got an error during execution of __exit__?
1046+
vm.call_method(
1047+
context_manager,
1048+
"__exit__",
1049+
vec![vm.ctx.none(), vm.ctx.none(), vm.ctx.none()],
1050+
)
1051+
}
1052+
1053+
fn call_context_manager_exit(
1054+
&self,
1055+
vm: &VirtualMachine,
1056+
context_manager: &PyObjectRef,
1057+
exc: PyObjectRef,
1058+
) -> PyResult {
1059+
// TODO: do we want to put the exit call on the stack?
1060+
// TODO: what happens when we got an error during execution of __exit__?
1061+
let exc_type = exc.class().into_object();
1062+
let exc_val = exc.clone();
1063+
let exc_tb = vm.ctx.none(); // TODO: retrieve traceback?
1064+
vm.call_method(context_manager, "__exit__", vec![exc_type, exc_val, exc_tb])
10641065
}
10651066

10661067
fn store_name(
@@ -1131,7 +1132,7 @@ impl Frame {
11311132

11321133
fn jump(&self, label: bytecode::Label) {
11331134
let target_pc = self.code.label_map[&label];
1134-
trace!("program counter from {:?} to {:?}", self.lasti, target_pc);
1135+
trace!("jump from {:?} to {:?}", self.lasti, target_pc);
11351136
*self.lasti.borrow_mut() = target_pc;
11361137
}
11371138

vm/src/obj/objbool.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ impl TryFromObject for bool {
1919
}
2020
}
2121

22+
/// Convert Python bool into Rust bool.
2223
pub fn boolval(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<bool> {
2324
Ok(if let Ok(f) = vm.get_method(obj.clone(), "__bool__") {
2425
let bool_res = vm.invoke(f, PyFuncArgs::default())?;

vm/src/obj/objtype.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ fn type_dict_setter(_instance: PyClassRef, _value: PyObjectRef, vm: &VirtualMach
289289
))
290290
}
291291

292-
// This is the internal get_attr implementation for fast lookup on a class.
292+
/// This is the internal get_attr implementation for fast lookup on a class.
293293
pub fn class_get_attr(class: &PyClassRef, attr_name: &str) -> Option<PyObjectRef> {
294294
if let Some(item) = class.attributes.borrow().get(attr_name).cloned() {
295295
return Some(item);

vm/src/pyobject.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ pub type PyResult<T = PyObjectRef> = Result<T, PyObjectRef>; // A valid value, o
8787

8888
/// For attributes we do not use a dict, but a hashmap. This is probably
8989
/// faster, unordered, and only supports strings as keys.
90+
/// TODO: class attributes should maintain insertion order (use IndexMap here)
9091
pub type PyAttributes = HashMap<String, PyObjectRef>;
9192

9293
impl fmt::Display for PyObject<dyn PyObjectPayload> {
@@ -833,6 +834,7 @@ impl<T: PyValue> PyRef<T> {
833834
pub fn as_object(&self) -> &PyObjectRef {
834835
&self.obj
835836
}
837+
836838
pub fn into_object(self) -> PyObjectRef {
837839
self.obj
838840
}

0 commit comments

Comments
 (0)