diff --git a/crates/dash_compiler/src/builder.rs b/crates/dash_compiler/src/builder.rs index a428778e..aa393fd5 100755 --- a/crates/dash_compiler/src/builder.rs +++ b/crates/dash_compiler/src/builder.rs @@ -7,7 +7,7 @@ use dash_middle::compiler::instruction::Instruction; use crate::jump_container::JumpContainer; use crate::{jump_container, FunctionCompiler}; -#[derive(PartialOrd, Ord, Hash, Eq, PartialEq, Debug, Clone)] +#[derive(PartialOrd, Ord, Hash, Eq, PartialEq, Debug, Clone, Copy)] pub enum Label { IfEnd, /// A branch of an if statement @@ -33,6 +33,9 @@ pub enum Label { switch_id: usize, }, Catch, + Finally { + finally_id: usize, + }, TryEnd, InitParamWithDefaultValue, FinishParamDefaultValueInit, diff --git a/crates/dash_compiler/src/instruction.rs b/crates/dash_compiler/src/instruction.rs index b94a8a55..0b884a0b 100755 --- a/crates/dash_compiler/src/instruction.rs +++ b/crates/dash_compiler/src/instruction.rs @@ -87,10 +87,25 @@ impl<'cx, 'interner> InstructionBuilder<'cx, 'interner> { Ok(()) } - pub fn build_try_block(&mut self) { + fn write_bool(&mut self, b: bool) { + self.write(b.into()); + } + + pub fn build_try_block(&mut self, has_catch: bool, finally_id: Option) { self.write_instr(Instruction::Try); - self.write_all(&[0, 0]); + self.write_bool(has_catch); + if has_catch { + self.write_all(&[0, 0]); + } + // NOTE: even though we won't *really* perform a jump (we skip over the following `jump` instruction emitted by this call in the vm dispatcher) + // we use the local jump resolving mechanism for updating the catch offset self.add_local_jump(Label::Catch); + self.write_bool(finally_id.is_some()); + if let Some(finally_id) = finally_id { + self.write_all(&[0, 0]); + self.current_function_mut() + .add_global_jump(Label::Finally { finally_id }); + } } pub fn build_local_load(&mut self, index: u16, is_extern: bool) { @@ -99,7 +114,8 @@ impl<'cx, 'interner> InstructionBuilder<'cx, 'interner> { pub fn build_global_load(&mut self, ident: Symbol) -> Result<(), LimitExceededError> { let id = self.current_function_mut().cp.add(Constant::Identifier(ident))?; - self.write_wide_instr(Instruction::LdGlobal, Instruction::LdGlobalW, id); + self.write_instr(Instruction::LdGlobal); + self.writew(id); Ok(()) } diff --git a/crates/dash_compiler/src/lib.rs b/crates/dash_compiler/src/lib.rs index 126d5f60..fa225ba2 100644 --- a/crates/dash_compiler/src/lib.rs +++ b/crates/dash_compiler/src/lib.rs @@ -23,6 +23,7 @@ use dash_middle::parser::statement::{ VariableDeclaration, VariableDeclarationKind, VariableDeclarationName, VariableDeclarations, WhileLoop, }; use dash_middle::sourcemap::Span; +use dash_middle::util::Counter; use dash_middle::visitor::Visitor; use dash_optimizer::consteval::ConstFunctionEvalCtx; use dash_optimizer::type_infer::TypeInferCtx; @@ -64,8 +65,11 @@ struct FunctionLocalState { /// /// Bytecode can refer to constants using the [Instruction::Constant] instruction, followed by a u8 index. cp: ConstantPool, - /// Current try catch depth - try_catch_depth: u16, + /// Current `try` depth (note that this does NOT include `catch`es) + try_depth: u16, + /// A stack of try-catch-finally blocks and their optional `finally` label that can be jumped to + finally_labels: Vec>, + finally_counter: Counter, /// The type of function that this FunctionCompiler compiles ty: FunctionKind, /// Container, used for storing global labels that can be jumped to @@ -89,7 +93,9 @@ impl FunctionLocalState { Self { buf: Vec::new(), cp: ConstantPool::new(), - try_catch_depth: 0, + try_depth: 0, + finally_labels: Vec::new(), + finally_counter: Counter::new(), ty, jc: JumpContainer::new(), breakables: Vec::new(), @@ -120,6 +126,7 @@ impl FunctionLocalState { self.switch_counter += 1; switch_id } + fn exit_loop(&mut self) { let item = self.breakables.pop(); match item { @@ -151,6 +158,17 @@ impl FunctionLocalState { FunctionKind::Generator | FunctionKind::Arrow => false, } } + + pub fn is_generator_or_async(&self) -> bool { + matches!( + self.ty, + FunctionKind::Function(Asyncness::Yes) | FunctionKind::Generator + ) + } + + fn enclosing_finally(&self) -> Option