Skip to content

Commit 2c2925a

Browse files
committed
Support reraise
1 parent 51aa817 commit 2c2925a

File tree

4 files changed

+51
-16
lines changed

4 files changed

+51
-16
lines changed

tests/snippets/try_exceptions.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,3 +125,15 @@ def __init__(self):
125125
except ZeroDivisionError as ex:
126126
assert type(ex.__cause__) == NameError
127127

128+
try:
129+
try:
130+
raise NameError
131+
except:
132+
raise
133+
except NameError:
134+
pass
135+
136+
try:
137+
raise
138+
except RuntimeError:
139+
pass

vm/src/bytecode.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ pub enum Instruction {
135135
PopBlock,
136136
Raise {
137137
argc: usize,
138+
in_exc: bool,
138139
},
139140
BuildString {
140141
size: usize,
@@ -363,7 +364,7 @@ impl Instruction {
363364
SetupWith { end } => w!(SetupWith, end),
364365
CleanupWith { end } => w!(CleanupWith, end),
365366
PopBlock => w!(PopBlock),
366-
Raise { argc } => w!(Raise, argc),
367+
Raise { argc, in_exc } => w!(Raise, argc, in_exc),
367368
BuildString { size } => w!(BuildString, size),
368369
BuildTuple { size, unpack } => w!(BuildTuple, size, unpack),
369370
BuildList { size, unpack } => w!(BuildList, size, unpack),

vm/src/compile.rs

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ struct Compiler {
2424
current_qualified_path: Option<String>,
2525
in_loop: bool,
2626
in_function_def: bool,
27+
in_exc_handler: bool,
2728
}
2829

2930
/// Compile a given sourcecode into a bytecode object.
@@ -85,6 +86,7 @@ impl Compiler {
8586
current_qualified_path: None,
8687
in_loop: false,
8788
in_function_def: false,
89+
in_exc_handler: false,
8890
}
8991
}
9092

@@ -325,15 +327,24 @@ impl Compiler {
325327
match cause {
326328
Some(cause) => {
327329
self.compile_expression(cause)?;
328-
self.emit(Instruction::Raise { argc: 2 });
330+
self.emit(Instruction::Raise {
331+
argc: 2,
332+
in_exc: self.in_exc_handler,
333+
});
329334
}
330335
None => {
331-
self.emit(Instruction::Raise { argc: 1 });
336+
self.emit(Instruction::Raise {
337+
argc: 1,
338+
in_exc: self.in_exc_handler,
339+
});
332340
}
333341
}
334342
}
335343
None => {
336-
self.emit(Instruction::Raise { argc: 0 });
344+
self.emit(Instruction::Raise {
345+
argc: 0,
346+
in_exc: self.in_exc_handler,
347+
});
337348
}
338349
},
339350
ast::Statement::Try {
@@ -378,7 +389,10 @@ impl Compiler {
378389
});
379390
}
380391
}
381-
self.emit(Instruction::Raise { argc: 1 });
392+
self.emit(Instruction::Raise {
393+
argc: 1,
394+
in_exc: self.in_exc_handler,
395+
});
382396
self.set_label(end_label);
383397
}
384398
ast::Statement::Break => {
@@ -558,6 +572,7 @@ impl Compiler {
558572
self.emit(Instruction::Jump { target: else_label });
559573

560574
// except handlers:
575+
self.in_exc_handler = true;
561576
self.set_label(handler_label);
562577
// Exception is on top of stack now
563578
handler_label = self.new_label();
@@ -586,15 +601,10 @@ impl Compiler {
586601

587602
// We have a match, store in name (except x as y)
588603
if let Some(alias) = &handler.name {
604+
// Duplicate exception for context:
605+
self.emit(Instruction::Duplicate);
589606
self.store_name(alias);
590-
} else {
591-
// Drop exception from top of stack:
592-
self.emit(Instruction::Pop);
593607
}
594-
} else {
595-
// Catch all!
596-
// Drop exception from top of stack:
597-
self.emit(Instruction::Pop);
598608
}
599609

600610
// Handler code:
@@ -611,6 +621,9 @@ impl Compiler {
611621
target: handler_label,
612622
});
613623
self.set_label(handler_label);
624+
// Drop exception from top of stack:
625+
self.emit(Instruction::Pop);
626+
self.in_exc_handler = false;
614627
// If code flows here, we have an unhandled exception,
615628
// emit finally code and raise again!
616629
// Duplicate finally code here:
@@ -619,7 +632,10 @@ impl Compiler {
619632
if let Some(statements) = finalbody {
620633
self.compile_statements(statements)?;
621634
}
622-
self.emit(Instruction::Raise { argc: 1 });
635+
self.emit(Instruction::Raise {
636+
argc: 1,
637+
in_exc: false,
638+
});
623639

624640
// We successfully ran the try block:
625641
// else:

vm/src/frame.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -715,14 +715,20 @@ impl Frame {
715715
Ok(None)
716716
}
717717

718-
bytecode::Instruction::Raise { argc } => {
718+
bytecode::Instruction::Raise { argc, in_exc } => {
719+
if argc.clone() == 0 && in_exc.clone() == false {
720+
return Err(vm.new_exception(
721+
vm.ctx.exceptions.runtime_error.clone(),
722+
"No active exception to reraise".to_string(),
723+
));
724+
}
719725
let cause = match argc {
720726
2 => self.get_exception(vm, true)?,
721727
_ => vm.get_none(),
722728
};
723729
let exception = match argc {
724-
1 | 2 => self.get_exception(vm, false)?,
725-
0 | 3 => panic!("Not implemented!"),
730+
0 | 1 | 2 => self.get_exception(vm, false)?,
731+
3 => panic!("Not implemented!"),
726732
_ => panic!("Invalid parameter for RAISE_VARARGS, must be between 0 to 3"),
727733
};
728734
info!("Exception raised: {:?} with cause: {:?}", exception, cause);

0 commit comments

Comments
 (0)