diff --git a/crates/oxide_compiler/src/stmt/basic/break_continue.rs b/crates/oxide_compiler/src/stmt/basic/break_continue.rs index e33fd5c..d9f4bd3 100644 --- a/crates/oxide_compiler/src/stmt/basic/break_continue.rs +++ b/crates/oxide_compiler/src/stmt/basic/break_continue.rs @@ -1,5 +1,4 @@ use crate::compiler::{CompileCtx, Compiler}; -use oxide_bytecode::opcode; impl Compiler { pub(super) fn count_break_statement(&self, ctx: &mut CompileCtx) { @@ -25,10 +24,7 @@ impl Compiler { let (bl, _) = ctx.current_loop().ok_or("break outside switch or loop".to_string())?; *bl }; - let break_pos = ctx.resolve_label(break_label)?; - let offset = (break_pos as isize) - (ctx.bytecode.len() as isize); - let offset = ctx.checked_jump_offset(offset); - ctx.emit(opcode::encode_jmp(offset)); + ctx.emit_jmp_labeled(break_label); Ok(None) } @@ -47,10 +43,7 @@ impl Compiler { let (_, cl) = ctx.current_loop().ok_or("continue outside loop".to_string())?; *cl }; - let continue_pos = ctx.resolve_label(continue_label)?; - let offset = (continue_pos as isize) - (ctx.bytecode.len() as isize); - let offset = ctx.checked_jump_offset(offset); - ctx.emit(opcode::encode_jmp(offset)); + ctx.emit_jmp_labeled(continue_label); Ok(None) } } diff --git a/crates/oxide_compiler/src/stmt/basic/labeled.rs b/crates/oxide_compiler/src/stmt/basic/labeled.rs index 57c5f1c..dd15f4f 100644 --- a/crates/oxide_compiler/src/stmt/basic/labeled.rs +++ b/crates/oxide_compiler/src/stmt/basic/labeled.rs @@ -42,6 +42,7 @@ impl Compiler { let id = ctx.next_label_id(); ctx.push_label_scope(name, Label::LabeledEnd(id), None)?; self.emit_statement(&stmt.body, ctx)?; + ctx.labels.label_map.insert(Label::LabeledEnd(id), ctx.bytecode.len()); ctx.pop_label_scope(); } Ok(None) diff --git a/crates/oxide_compiler/src/stmt/control.rs b/crates/oxide_compiler/src/stmt/control.rs index f402f5f..a98fe3c 100644 --- a/crates/oxide_compiler/src/stmt/control.rs +++ b/crates/oxide_compiler/src/stmt/control.rs @@ -35,10 +35,7 @@ impl Compiler { let test_reg = self.emit_expression(&ifs.test, ctx)?; - let else_pos = ctx.resolve_label(else_label)?; - let offset = (else_pos as isize) - (ctx.bytecode.len() as isize); - let offset = ctx.checked_jump_offset(offset); - ctx.emit(opcode::encode_jmp_if_false(test_reg, offset)); + ctx.emit_jmp_if_false_labeled(test_reg, else_label); let cons_reg = self.emit_statement(&ifs.consequent, ctx)?; let result_reg = ctx.alloc_reg(); @@ -50,12 +47,10 @@ impl Compiler { } if ifs.alternate.is_some() { - let end_pos = ctx.resolve_label(end_label)?; - let offset = (end_pos as isize) - (ctx.bytecode.len() as isize); - let offset = ctx.checked_jump_offset(offset); - ctx.emit(opcode::encode_jmp(offset)); + ctx.emit_jmp_labeled(end_label); } + ctx.labels.label_map.insert(else_label, ctx.bytecode.len()); if let Some(alt) = &ifs.alternate { let alt_reg = self.emit_statement(alt, ctx)?; if let Some(r) = alt_reg { @@ -66,6 +61,8 @@ impl Compiler { } } + ctx.labels.label_map.insert(end_label, ctx.bytecode.len()); + Ok(Some(result_reg)) } diff --git a/crates/oxide_compiler/src/stmt/exception/try_catch.rs b/crates/oxide_compiler/src/stmt/exception/try_catch.rs index d987fe7..43f268f 100644 --- a/crates/oxide_compiler/src/stmt/exception/try_catch.rs +++ b/crates/oxide_compiler/src/stmt/exception/try_catch.rs @@ -65,14 +65,12 @@ impl Compiler { let has_finally = ts.finalizer.is_some(); let result_reg = ctx.alloc_reg(); let mut try_finally_begin_pos: Option = None; - let mut try_begin_pos: Option = None; if has_finally { try_finally_begin_pos = Some(ctx.bytecode.len()); ctx.emit(opcode::encode_try_finally_begin(0)); } if has_catch { - try_begin_pos = Some(ctx.bytecode.len()); - ctx.emit(opcode::encode_try_begin(0)); + ctx.emit_try_begin_labeled(catch_label); } let mut last_try_result: Option = None; for s in &ts.block.body { @@ -85,20 +83,12 @@ impl Compiler { ctx.emit(opcode::encode(OpCode::TRY_END, 0, 0, 0)); } let jmp_needed = has_catch || has_finally; - let jmp_skip_pos = if jmp_needed { - let pos = ctx.bytecode.len(); - ctx.emit(opcode::encode_jmp(0)); - Some(pos) - } else { - None - }; + if jmp_needed { + let target = if has_finally { Label::FinallyBody(id) } else { try_end_label }; + ctx.emit_jmp_labeled(target); + } let catch_label_pc = ctx.bytecode.len(); ctx.labels.label_map.insert(catch_label, catch_label_pc); - if let Some(try_begin_pc) = try_begin_pos { - let offset = catch_label_pc as isize - (try_begin_pc as isize); - let offset = ctx.checked_jump_offset(offset); - ctx.bytecode[try_begin_pc] = opcode::encode_try_begin(offset); - } if let Some(catch) = &ts.handler { ctx.push_scope(); if let Some(param) = &catch.param { @@ -126,11 +116,6 @@ impl Compiler { let offset = ctx.checked_jump_offset(offset); ctx.bytecode[fb_pos] = opcode::encode_try_finally_begin(offset); } - if let Some(jmp_pos) = jmp_skip_pos { - let offset = finally_label_pc as isize - (jmp_pos as isize); - let offset = ctx.checked_jump_offset(offset); - ctx.bytecode[jmp_pos] = opcode::encode_jmp(offset); - } let mut last_finally_result: Option = None; for s in &ts.finalizer.as_ref().unwrap().body { if let Some(r) = self.emit_statement(s, ctx)? { @@ -139,10 +124,6 @@ impl Compiler { } ctx.emit(opcode::encode(OpCode::LOAD_VAR, result_reg, last_finally_result.unwrap_or(result_reg), 0)); ctx.emit(opcode::encode(OpCode::TRY_FINALLY_END, 0, 0, 0)); - } else if let Some(jmp_pos) = jmp_skip_pos { - let offset = ctx.bytecode.len() as isize - (jmp_pos as isize); - let offset = ctx.checked_jump_offset(offset); - ctx.bytecode[jmp_pos] = opcode::encode_jmp(offset); } let try_end_pc = ctx.bytecode.len(); ctx.labels.label_map.insert(try_end_label, try_end_pc); diff --git a/crates/oxide_compiler/src/stmt/switch.rs b/crates/oxide_compiler/src/stmt/switch.rs index 3e32ed2..d9f075e 100644 --- a/crates/oxide_compiler/src/stmt/switch.rs +++ b/crates/oxide_compiler/src/stmt/switch.rs @@ -50,25 +50,22 @@ impl Compiler { let eq_reg = ctx.alloc_reg(); ctx.emit(opcode::encode(OpCode::EQ, eq_reg, disc_reg, test_reg)); let case_label = Label::SwitchCase(id, case_idx as u32); - let body_pos = ctx.resolve_label(case_label)?; - let offset = (body_pos as isize) - (ctx.bytecode.len() as isize); - let offset = ctx.checked_jump_offset(offset); - ctx.emit(opcode::encode_jmp_if_true(eq_reg, offset)); + ctx.emit_jmp_if_true_labeled(eq_reg, case_label); ctx.restore_reg_checkpoint(compare_reg_checkpoint); } } let has_default = cases.iter().any(|c| c.test.is_none()); if !has_default { - let end_pos = ctx.resolve_label(end_label)?; - let offset = (end_pos as isize) - (ctx.bytecode.len() as isize); - let offset = ctx.checked_jump_offset(offset); - ctx.emit(opcode::encode_jmp(offset)); + ctx.emit_jmp_labeled(end_label); } - for case in cases.iter() { + for (case_idx, case) in cases.iter().enumerate() { + let case_label = Label::SwitchCase(id, case_idx as u32); + ctx.labels.label_map.insert(case_label, ctx.bytecode.len()); for s in &case.consequent { self.emit_statement(s, ctx)?; } } + ctx.labels.label_map.insert(end_label, ctx.bytecode.len()); ctx.pop_switch(); Ok(None) }