diff --git a/crates/oxide_compiler/src/emitter.rs b/crates/oxide_compiler/src/emitter.rs index b9c89d8..92844fd 100644 --- a/crates/oxide_compiler/src/emitter.rs +++ b/crates/oxide_compiler/src/emitter.rs @@ -1029,9 +1029,7 @@ impl Compiler { _ => OpCode::CALL, }; ctx.emit(opcode::encode(op, callee_reg, this_reg, first_arg_reg)); - if matches!(op, OpCode::CALL_NATIVE) { - ctx.emit(arg_regs.len() as u32); - } + ctx.emit(arg_regs.len() as u32); // Copy result from regs[0] into a dedicated register so multiple // call expressions don't overwrite each other. let result_reg = ctx.alloc_reg(); diff --git a/crates/oxide_vm/src/vm.rs b/crates/oxide_vm/src/vm.rs index e3455f3..77e6fbc 100644 --- a/crates/oxide_vm/src/vm.rs +++ b/crates/oxide_vm/src/vm.rs @@ -1191,12 +1191,13 @@ impl Vm { if !obj_ptr.is_null() { let obj = unsafe { &*obj_ptr }; if obj.is_function() { - if obj.native_fn().is_some() { - // Native call - use extension word for arg_count - let ext = self.bytecode[self.pc]; - self.pc += 1; - let arg_count = (ext & 0xFF) as usize; + // Always consume extension word for arg_count + let ext = self.bytecode[self.pc]; + self.pc += 1; + let arg_count = (ext & 0xFF) as usize; + if obj.native_fn().is_some() { + // Native call let mut args_buf = [0u8; 257]; args_buf[0] = this_reg; for i in 0..arg_count.min(256) { diff --git a/crates/oxide_vm/tests/regression_tests.rs b/crates/oxide_vm/tests/regression_tests.rs index 5ea070b..1997b5e 100644 --- a/crates/oxide_vm/tests/regression_tests.rs +++ b/crates/oxide_vm/tests/regression_tests.rs @@ -59,9 +59,10 @@ fn regression_recursion_depth_limit() { #[test] fn regression_throw_statement_errors() { - assert_eq!( - eval("throw 'error'"), - "vm error: opcode THROW not yet implemented" + let result = eval("throw 'error'"); + assert!( + result.contains("uncaught"), + "expected uncaught, got: {result}" ); }