mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
feat: 统一内部报错模型异常抛出风格
This commit is contained in:
@@ -462,8 +462,7 @@ impl Compiler {
|
|||||||
ctx.label_map.insert(finally_label, finally_label_pc);
|
ctx.label_map.insert(finally_label, finally_label_pc);
|
||||||
if let Some(fb_pos) = try_finally_begin_pos {
|
if let Some(fb_pos) = try_finally_begin_pos {
|
||||||
let offset = finally_label_pc as isize - (fb_pos as isize);
|
let offset = finally_label_pc as isize - (fb_pos as isize);
|
||||||
ctx.bytecode[fb_pos] =
|
ctx.bytecode[fb_pos] = opcode::encode_try_finally_begin(offset as i16);
|
||||||
opcode::encode_try_finally_begin(offset as i16);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(jmp_pos) = jmp_skip_pos {
|
if let Some(jmp_pos) = jmp_skip_pos {
|
||||||
|
|||||||
@@ -47,6 +47,11 @@ pub fn create_type_error(vm: &mut Vm, msg: &str) -> JsValue {
|
|||||||
create_error_object(vm, proto_ptr, "TypeError", msg)
|
create_error_object(vm, proto_ptr, "TypeError", msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn create_error(vm: &mut Vm, msg: &str) -> JsValue {
|
||||||
|
let proto_ptr = P::as_ptr(&vm.kernel().builtin_world().error_proto) as *mut JsObject;
|
||||||
|
create_error_object(vm, proto_ptr, "Error", msg)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn create_reference_error(vm: &mut Vm, msg: &str) -> JsValue {
|
pub fn create_reference_error(vm: &mut Vm, msg: &str) -> JsValue {
|
||||||
let proto_ptr = P::as_ptr(&vm.kernel().builtin_world().reference_error_proto) as *mut JsObject;
|
let proto_ptr = P::as_ptr(&vm.kernel().builtin_world().reference_error_proto) as *mut JsObject;
|
||||||
create_error_object(vm, proto_ptr, "ReferenceError", msg)
|
create_error_object(vm, proto_ptr, "ReferenceError", msg)
|
||||||
|
|||||||
+75
-38
@@ -36,6 +36,37 @@ macro_rules! native_call {
|
|||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused_macros)]
|
||||||
|
macro_rules! throw_err {
|
||||||
|
($self:ident, Error, $msg:expr) => {{
|
||||||
|
let error = crate::builtins::error::create_error($self, $msg);
|
||||||
|
$self.exception_value = Some(error);
|
||||||
|
$self.pending_error_kind = Some("Error");
|
||||||
|
match $self.unwind() {
|
||||||
|
Ok(()) => continue,
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
($self:ident, TypeError, $msg:expr) => {{
|
||||||
|
let error = crate::builtins::error::create_type_error($self, $msg);
|
||||||
|
$self.exception_value = Some(error);
|
||||||
|
$self.pending_error_kind = Some("TypeError");
|
||||||
|
match $self.unwind() {
|
||||||
|
Ok(()) => continue,
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
($self:ident, ReferenceError, $msg:expr) => {{
|
||||||
|
let error = crate::builtins::error::create_reference_error($self, $msg);
|
||||||
|
$self.exception_value = Some(error);
|
||||||
|
$self.pending_error_kind = Some("ReferenceError");
|
||||||
|
match $self.unwind() {
|
||||||
|
Ok(()) => continue,
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
pub struct CallFrame {
|
pub struct CallFrame {
|
||||||
pub return_addr: usize,
|
pub return_addr: usize,
|
||||||
pub n_locals: u8,
|
pub n_locals: u8,
|
||||||
@@ -965,11 +996,9 @@ impl Vm {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let msg = self
|
let exc = self.exception_value.take().unwrap_or(JsValue::undefined());
|
||||||
.exception_value
|
let kind_str = self.pending_error_kind.take().unwrap_or("Error");
|
||||||
.take()
|
let msg = format!("uncaught {kind_str}: {exc}");
|
||||||
.map(|v| format!("uncaught {v}"))
|
|
||||||
.unwrap_or_else(|| "uncaught exception".to_string());
|
|
||||||
Err(msg)
|
Err(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1271,7 +1300,7 @@ impl Vm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Err("TypeError: CALL target is not callable".into());
|
throw_err!(self, TypeError, "CALL target is not callable");
|
||||||
}
|
}
|
||||||
|
|
||||||
OpCode::CALL_NATIVE => {
|
OpCode::CALL_NATIVE => {
|
||||||
@@ -1282,15 +1311,19 @@ impl Vm {
|
|||||||
let callee = self.regs[callee_reg];
|
let callee = self.regs[callee_reg];
|
||||||
|
|
||||||
if !callee.is_object() {
|
if !callee.is_object() {
|
||||||
return Err("TypeError: CALL_NATIVE target is not an object".into());
|
throw_err!(self, TypeError, "CALL_NATIVE target is not an object");
|
||||||
}
|
}
|
||||||
let obj_ptr = callee.as_js_object_ptr();
|
let obj_ptr = callee.as_js_object_ptr();
|
||||||
if obj_ptr.is_null() {
|
if obj_ptr.is_null() {
|
||||||
return Err("TypeError: CALL_NATIVE target is null".into());
|
throw_err!(self, TypeError, "CALL_NATIVE target is null");
|
||||||
}
|
}
|
||||||
let obj = unsafe { &*obj_ptr };
|
let obj = unsafe { &*obj_ptr };
|
||||||
if !obj.is_function() || obj.native_fn().is_none() {
|
if !obj.is_function() || obj.native_fn().is_none() {
|
||||||
return Err("TypeError: CALL_NATIVE target is not a native function".into());
|
throw_err!(
|
||||||
|
self,
|
||||||
|
TypeError,
|
||||||
|
"CALL_NATIVE target is not a native function"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let ext = self.bytecode[self.pc];
|
let ext = self.bytecode[self.pc];
|
||||||
@@ -1320,18 +1353,22 @@ impl Vm {
|
|||||||
|
|
||||||
let constructor = self.regs[constructor_reg];
|
let constructor = self.regs[constructor_reg];
|
||||||
if !constructor.is_object() {
|
if !constructor.is_object() {
|
||||||
return Err(
|
throw_err!(
|
||||||
"TypeError: NEW_EXPRESSION: constructor is not an object".into()
|
self,
|
||||||
|
TypeError,
|
||||||
|
"NEW_EXPRESSION: constructor is not an object"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let ctor_ptr = constructor.as_js_object_ptr();
|
let ctor_ptr = constructor.as_js_object_ptr();
|
||||||
if ctor_ptr.is_null() {
|
if ctor_ptr.is_null() {
|
||||||
return Err("TypeError: NEW_EXPRESSION: constructor is null".into());
|
throw_err!(self, TypeError, "NEW_EXPRESSION: constructor is null");
|
||||||
}
|
}
|
||||||
let ctor_obj = unsafe { &*ctor_ptr };
|
let ctor_obj = unsafe { &*ctor_ptr };
|
||||||
if !ctor_obj.is_function() {
|
if !ctor_obj.is_function() {
|
||||||
return Err(
|
throw_err!(
|
||||||
"TypeError: NEW_EXPRESSION: constructor is not a function".into()
|
self,
|
||||||
|
TypeError,
|
||||||
|
"NEW_EXPRESSION: constructor is not a function"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1436,7 +1473,7 @@ impl Vm {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Err("TypeError: IC_GET_PROP on non-object".into());
|
throw_err!(self, TypeError, "IC_GET_PROP on non-object");
|
||||||
}
|
}
|
||||||
let obj = unsafe { &*obj_ptr };
|
let obj = unsafe { &*obj_ptr };
|
||||||
let prop_name_si = self.regs[b].as_string_index();
|
let prop_name_si = self.regs[b].as_string_index();
|
||||||
@@ -1491,7 +1528,7 @@ impl Vm {
|
|||||||
OpCode::IC_SET_PROP => {
|
OpCode::IC_SET_PROP => {
|
||||||
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
|
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
|
||||||
if obj_ptr.is_null() {
|
if obj_ptr.is_null() {
|
||||||
return Err("TypeError: IC_SET_PROP on non-object".into());
|
throw_err!(self, TypeError, "IC_SET_PROP on non-object");
|
||||||
}
|
}
|
||||||
let obj = unsafe { &mut *obj_ptr };
|
let obj = unsafe { &mut *obj_ptr };
|
||||||
let prop_name_si = self.regs[b].as_string_index();
|
let prop_name_si = self.regs[b].as_string_index();
|
||||||
@@ -1547,7 +1584,7 @@ impl Vm {
|
|||||||
OpCode::GET_PROP => {
|
OpCode::GET_PROP => {
|
||||||
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
|
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
|
||||||
if obj_ptr.is_null() {
|
if obj_ptr.is_null() {
|
||||||
return Err("TypeError: GET_PROP on non-object".into());
|
throw_err!(self, TypeError, "GET_PROP on non-object");
|
||||||
}
|
}
|
||||||
let obj = unsafe { &*obj_ptr };
|
let obj = unsafe { &*obj_ptr };
|
||||||
let prop_name_si = self.regs[b].as_string_index();
|
let prop_name_si = self.regs[b].as_string_index();
|
||||||
@@ -1558,7 +1595,7 @@ impl Vm {
|
|||||||
OpCode::SET_PROP => {
|
OpCode::SET_PROP => {
|
||||||
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
|
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
|
||||||
if obj_ptr.is_null() {
|
if obj_ptr.is_null() {
|
||||||
return Err("TypeError: SET_PROP on non-object".into());
|
throw_err!(self, TypeError, "SET_PROP on non-object");
|
||||||
}
|
}
|
||||||
let obj = unsafe { &mut *obj_ptr };
|
let obj = unsafe { &mut *obj_ptr };
|
||||||
let prop_name_si = self.regs[b].as_string_index();
|
let prop_name_si = self.regs[b].as_string_index();
|
||||||
@@ -1582,12 +1619,12 @@ impl Vm {
|
|||||||
OpCode::GET_PROP_DYNAMIC => {
|
OpCode::GET_PROP_DYNAMIC => {
|
||||||
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
|
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
|
||||||
if obj_ptr.is_null() {
|
if obj_ptr.is_null() {
|
||||||
return Err("TypeError: GET_PROP_DYNAMIC on non-object".into());
|
throw_err!(self, TypeError, "GET_PROP_DYNAMIC on non-object");
|
||||||
}
|
}
|
||||||
let obj = unsafe { &*obj_ptr };
|
let obj = unsafe { &*obj_ptr };
|
||||||
let key_val = self.regs[a];
|
let key_val = self.regs[a];
|
||||||
if !key_val.is_string() {
|
if !key_val.is_string() {
|
||||||
return Err("TypeError: GET_PROP_DYNAMIC key not a string".into());
|
throw_err!(self, TypeError, "GET_PROP_DYNAMIC key not a string");
|
||||||
}
|
}
|
||||||
let prop_name_si = key_val.as_string_index();
|
let prop_name_si = key_val.as_string_index();
|
||||||
self.regs[b] = self
|
self.regs[b] = self
|
||||||
@@ -1598,12 +1635,12 @@ impl Vm {
|
|||||||
OpCode::SET_PROP_DYNAMIC => {
|
OpCode::SET_PROP_DYNAMIC => {
|
||||||
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
|
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
|
||||||
if obj_ptr.is_null() {
|
if obj_ptr.is_null() {
|
||||||
return Err("TypeError: SET_PROP_DYNAMIC on non-object".into());
|
throw_err!(self, TypeError, "SET_PROP_DYNAMIC on non-object");
|
||||||
}
|
}
|
||||||
let obj = unsafe { &mut *obj_ptr };
|
let obj = unsafe { &mut *obj_ptr };
|
||||||
let key_val = self.regs[a];
|
let key_val = self.regs[a];
|
||||||
if !key_val.is_string() {
|
if !key_val.is_string() {
|
||||||
return Err("TypeError: SET_PROP_DYNAMIC key not a string".into());
|
throw_err!(self, TypeError, "SET_PROP_DYNAMIC key not a string");
|
||||||
}
|
}
|
||||||
let prop_name_si = key_val.as_string_index();
|
let prop_name_si = key_val.as_string_index();
|
||||||
if let Some(pos) = self
|
if let Some(pos) = self
|
||||||
@@ -1649,7 +1686,7 @@ impl Vm {
|
|||||||
OpCode::SET_ELEM => {
|
OpCode::SET_ELEM => {
|
||||||
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
|
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
|
||||||
if obj_ptr.is_null() {
|
if obj_ptr.is_null() {
|
||||||
return Err("TypeError: SET_ELEM on non-object".into());
|
throw_err!(self, TypeError, "SET_ELEM on non-object");
|
||||||
}
|
}
|
||||||
let idx = self.regs[a].as_int() as usize;
|
let idx = self.regs[a].as_int() as usize;
|
||||||
let obj = unsafe { &mut *obj_ptr };
|
let obj = unsafe { &mut *obj_ptr };
|
||||||
@@ -1734,13 +1771,13 @@ impl Vm {
|
|||||||
let key_val = self.regs[a];
|
let key_val = self.regs[a];
|
||||||
let obj_ptr = self.regs[b].as_object_ptr() as *mut JsObject;
|
let obj_ptr = self.regs[b].as_object_ptr() as *mut JsObject;
|
||||||
if obj_ptr.is_null() {
|
if obj_ptr.is_null() {
|
||||||
return Err("TypeError: IN right-hand side is not an object".into());
|
throw_err!(self, TypeError, "IN right-hand side is not an object");
|
||||||
}
|
}
|
||||||
let obj = unsafe { &*obj_ptr };
|
let obj = unsafe { &*obj_ptr };
|
||||||
let prop_name_si = if key_val.is_string() {
|
let prop_name_si = if key_val.is_string() {
|
||||||
key_val.as_string_index()
|
key_val.as_string_index()
|
||||||
} else {
|
} else {
|
||||||
return Err("TypeError: IN key must be a string".into());
|
throw_err!(self, TypeError, "IN key must be a string");
|
||||||
};
|
};
|
||||||
let found = self.resolve_property(obj, prop_name_si).is_some();
|
let found = self.resolve_property(obj, prop_name_si).is_some();
|
||||||
self.regs[rd] = JsValue::bool(found);
|
self.regs[rd] = JsValue::bool(found);
|
||||||
@@ -1793,7 +1830,7 @@ impl Vm {
|
|||||||
OpCode::MEMBER_INC => {
|
OpCode::MEMBER_INC => {
|
||||||
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
|
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
|
||||||
if obj_ptr.is_null() {
|
if obj_ptr.is_null() {
|
||||||
return Err("TypeError: MEMBER_INC on non-object".into());
|
throw_err!(self, TypeError, "MEMBER_INC on non-object");
|
||||||
}
|
}
|
||||||
let obj = unsafe { &mut *obj_ptr };
|
let obj = unsafe { &mut *obj_ptr };
|
||||||
let prop_name_si = self.regs[b].as_string_index();
|
let prop_name_si = self.regs[b].as_string_index();
|
||||||
@@ -1886,7 +1923,7 @@ impl Vm {
|
|||||||
OpCode::MEMBER_DEC => {
|
OpCode::MEMBER_DEC => {
|
||||||
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
|
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
|
||||||
if obj_ptr.is_null() {
|
if obj_ptr.is_null() {
|
||||||
return Err("TypeError: MEMBER_DEC on non-object".into());
|
throw_err!(self, TypeError, "MEMBER_DEC on non-object");
|
||||||
}
|
}
|
||||||
let obj = unsafe { &mut *obj_ptr };
|
let obj = unsafe { &mut *obj_ptr };
|
||||||
let prop_name_si = self.regs[b].as_string_index();
|
let prop_name_si = self.regs[b].as_string_index();
|
||||||
@@ -1979,12 +2016,12 @@ impl Vm {
|
|||||||
OpCode::DYN_MEMBER_INC => {
|
OpCode::DYN_MEMBER_INC => {
|
||||||
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
|
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
|
||||||
if obj_ptr.is_null() {
|
if obj_ptr.is_null() {
|
||||||
return Err("TypeError: DYN_MEMBER_INC on non-object".into());
|
throw_err!(self, TypeError, "DYN_MEMBER_INC on non-object");
|
||||||
}
|
}
|
||||||
let obj = unsafe { &mut *obj_ptr };
|
let obj = unsafe { &mut *obj_ptr };
|
||||||
let key_val = self.regs[a];
|
let key_val = self.regs[a];
|
||||||
if !key_val.is_string() {
|
if !key_val.is_string() {
|
||||||
return Err("TypeError: DYN_MEMBER_INC key not a string".into());
|
throw_err!(self, TypeError, "DYN_MEMBER_INC key not a string");
|
||||||
}
|
}
|
||||||
let prop_name_si = key_val.as_string_index();
|
let prop_name_si = key_val.as_string_index();
|
||||||
let prop_val = self
|
let prop_val = self
|
||||||
@@ -2014,12 +2051,12 @@ impl Vm {
|
|||||||
OpCode::DYN_MEMBER_DEC => {
|
OpCode::DYN_MEMBER_DEC => {
|
||||||
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
|
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
|
||||||
if obj_ptr.is_null() {
|
if obj_ptr.is_null() {
|
||||||
return Err("TypeError: DYN_MEMBER_DEC on non-object".into());
|
throw_err!(self, TypeError, "DYN_MEMBER_DEC on non-object");
|
||||||
}
|
}
|
||||||
let obj = unsafe { &mut *obj_ptr };
|
let obj = unsafe { &mut *obj_ptr };
|
||||||
let key_val = self.regs[a];
|
let key_val = self.regs[a];
|
||||||
if !key_val.is_string() {
|
if !key_val.is_string() {
|
||||||
return Err("TypeError: DYN_MEMBER_DEC key not a string".into());
|
throw_err!(self, TypeError, "DYN_MEMBER_DEC key not a string");
|
||||||
}
|
}
|
||||||
let prop_name_si = key_val.as_string_index();
|
let prop_name_si = key_val.as_string_index();
|
||||||
let prop_val = self
|
let prop_val = self
|
||||||
@@ -2049,7 +2086,7 @@ impl Vm {
|
|||||||
OpCode::COMPOUND_MEMBER_ADD => {
|
OpCode::COMPOUND_MEMBER_ADD => {
|
||||||
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
|
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
|
||||||
if obj_ptr.is_null() {
|
if obj_ptr.is_null() {
|
||||||
return Err("TypeError: COMPOUND_MEMBER_ADD on non-object".into());
|
throw_err!(self, TypeError, "COMPOUND_MEMBER_ADD on non-object");
|
||||||
}
|
}
|
||||||
let obj = unsafe { &mut *obj_ptr };
|
let obj = unsafe { &mut *obj_ptr };
|
||||||
let prop_name_si = self.regs[b].as_string_index();
|
let prop_name_si = self.regs[b].as_string_index();
|
||||||
@@ -2112,7 +2149,7 @@ impl Vm {
|
|||||||
OpCode::COMPOUND_MEMBER_SUB => {
|
OpCode::COMPOUND_MEMBER_SUB => {
|
||||||
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
|
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
|
||||||
if obj_ptr.is_null() {
|
if obj_ptr.is_null() {
|
||||||
return Err("TypeError: COMPOUND_MEMBER_SUB on non-object".into());
|
throw_err!(self, TypeError, "COMPOUND_MEMBER_SUB on non-object");
|
||||||
}
|
}
|
||||||
let obj = unsafe { &mut *obj_ptr };
|
let obj = unsafe { &mut *obj_ptr };
|
||||||
let prop_name_si = self.regs[b].as_string_index();
|
let prop_name_si = self.regs[b].as_string_index();
|
||||||
@@ -2166,7 +2203,7 @@ impl Vm {
|
|||||||
OpCode::COMPOUND_MEMBER_MUL => {
|
OpCode::COMPOUND_MEMBER_MUL => {
|
||||||
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
|
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
|
||||||
if obj_ptr.is_null() {
|
if obj_ptr.is_null() {
|
||||||
return Err("TypeError: COMPOUND_MEMBER_MUL on non-object".into());
|
throw_err!(self, TypeError, "COMPOUND_MEMBER_MUL on non-object");
|
||||||
}
|
}
|
||||||
let obj = unsafe { &mut *obj_ptr };
|
let obj = unsafe { &mut *obj_ptr };
|
||||||
let prop_name_si = self.regs[b].as_string_index();
|
let prop_name_si = self.regs[b].as_string_index();
|
||||||
@@ -2220,7 +2257,7 @@ impl Vm {
|
|||||||
OpCode::COMPOUND_MEMBER_DIV => {
|
OpCode::COMPOUND_MEMBER_DIV => {
|
||||||
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
|
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
|
||||||
if obj_ptr.is_null() {
|
if obj_ptr.is_null() {
|
||||||
return Err("TypeError: COMPOUND_MEMBER_DIV on non-object".into());
|
throw_err!(self, TypeError, "COMPOUND_MEMBER_DIV on non-object");
|
||||||
}
|
}
|
||||||
let obj = unsafe { &mut *obj_ptr };
|
let obj = unsafe { &mut *obj_ptr };
|
||||||
let prop_name_si = self.regs[b].as_string_index();
|
let prop_name_si = self.regs[b].as_string_index();
|
||||||
@@ -2274,7 +2311,7 @@ impl Vm {
|
|||||||
OpCode::COMPOUND_MEMBER_MOD => {
|
OpCode::COMPOUND_MEMBER_MOD => {
|
||||||
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
|
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
|
||||||
if obj_ptr.is_null() {
|
if obj_ptr.is_null() {
|
||||||
return Err("TypeError: COMPOUND_MEMBER_MOD on non-object".into());
|
throw_err!(self, TypeError, "COMPOUND_MEMBER_MOD on non-object");
|
||||||
}
|
}
|
||||||
let obj = unsafe { &mut *obj_ptr };
|
let obj = unsafe { &mut *obj_ptr };
|
||||||
let prop_name_si = self.regs[b].as_string_index();
|
let prop_name_si = self.regs[b].as_string_index();
|
||||||
@@ -2328,7 +2365,7 @@ impl Vm {
|
|||||||
OpCode::COMPOUND_MEMBER_EXP => {
|
OpCode::COMPOUND_MEMBER_EXP => {
|
||||||
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
|
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
|
||||||
if obj_ptr.is_null() {
|
if obj_ptr.is_null() {
|
||||||
return Err("TypeError: COMPOUND_MEMBER_EXP on non-object".into());
|
throw_err!(self, TypeError, "COMPOUND_MEMBER_EXP on non-object");
|
||||||
}
|
}
|
||||||
let obj = unsafe { &mut *obj_ptr };
|
let obj = unsafe { &mut *obj_ptr };
|
||||||
let prop_name_si = self.regs[b].as_string_index();
|
let prop_name_si = self.regs[b].as_string_index();
|
||||||
@@ -2382,7 +2419,7 @@ impl Vm {
|
|||||||
OpCode::FOR_IN_INIT => {
|
OpCode::FOR_IN_INIT => {
|
||||||
let obj_val = self.regs[a];
|
let obj_val = self.regs[a];
|
||||||
if !obj_val.is_object() {
|
if !obj_val.is_object() {
|
||||||
return Err("TypeError: for-in right-hand side is not an object".into());
|
throw_err!(self, TypeError, "for-in right-hand side is not an object");
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut keys_vec = bumpalo::collections::Vec::new_in(self.epoch.bump());
|
let mut keys_vec = bumpalo::collections::Vec::new_in(self.epoch.bump());
|
||||||
|
|||||||
@@ -75,3 +75,25 @@ fn test_try_catch_finally() {
|
|||||||
fn test_catch_param_binding() {
|
fn test_catch_param_binding() {
|
||||||
assert_eq!(eval("try { throw 99; } catch(myErr) { myErr; }"), "99");
|
assert_eq!(eval("try { throw 99; } catch(myErr) { myErr; }"), "99");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_throw_err_type_error_catchable() {
|
||||||
|
let result = eval("try { null.prop = 1; } catch(e) { 42; }");
|
||||||
|
assert_eq!(result, "42");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_throw_err_type_error_is_object() {
|
||||||
|
// IC_GET_PROP on null throws TypeError which is catchable; catch body runs
|
||||||
|
let result = eval("try { null.prop; } catch(e) { 99; }");
|
||||||
|
assert_eq!(result, "99");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_uncaught_type_error_message() {
|
||||||
|
let result = eval("null.prop;");
|
||||||
|
assert!(
|
||||||
|
result.contains("TypeError"),
|
||||||
|
"expected TypeError in message, got: {result}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user