From e37f117035f900e70e1a4a510c3e9e2c9d1d2f30 Mon Sep 17 00:00:00 2001 From: Windel Bouwman Date: Tue, 27 Aug 2019 21:16:59 +0200 Subject: [PATCH] Implement execution of finally block. Fixes #1306. --- src/compile.rs | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/compile.rs b/src/compile.rs index 70bc8f2..40a901e 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -712,13 +712,13 @@ impl Compiler { finalbody: &Option, ) -> Result<(), CompileError> { let mut handler_label = self.new_label(); - let finally_label = self.new_label(); + let finally_handler_label = self.new_label(); let else_label = self.new_label(); // Setup a finally block if we have a finally statement. if finalbody.is_some() { self.emit(Instruction::SetupFinally { - handler: finally_label, + handler: finally_handler_label, }); } @@ -773,26 +773,28 @@ impl Compiler { // Handler code: self.compile_statements(&handler.body)?; self.emit(Instruction::PopException); + + if finalbody.is_some() { + self.emit(Instruction::PopBlock); // pop finally block + // We enter the finally block, without exception. + self.emit(Instruction::EnterFinally); + } + self.emit(Instruction::Jump { - target: finally_label, + target: finally_handler_label, }); // Emit a new label for the next handler self.set_label(handler_label); handler_label = self.new_label(); } + self.emit(Instruction::Jump { target: handler_label, }); self.set_label(handler_label); // If code flows here, we have an unhandled exception, - // emit finally code and raise again! - // Duplicate finally code here: - // TODO: this bytecode is now duplicate, could this be - // improved? - if let Some(statements) = finalbody { - self.compile_statements(statements)?; - } + // raise the exception again! self.emit(Instruction::Raise { argc: 0 }); // We successfully ran the try block: @@ -802,8 +804,15 @@ impl Compiler { self.compile_statements(statements)?; } + if finalbody.is_some() { + self.emit(Instruction::PopBlock); // pop finally block + + // We enter the finally block, without return / exception. + self.emit(Instruction::EnterFinally); + } + // finally: - self.set_label(finally_label); + self.set_label(finally_handler_label); if let Some(statements) = finalbody { self.compile_statements(statements)?; self.emit(Instruction::EndFinally);