mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
feat: 支持对象进行完整 ES 属性解析
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
use crate::object::JsObject;
|
||||
use crate::shape::EMPTY_SHAPE_ID;
|
||||
use crate::value::JsValue;
|
||||
use crate::vm::Vm;
|
||||
|
||||
@@ -184,6 +186,25 @@ pub fn string_concat(lhs: &str, rhs: &str) -> String {
|
||||
s
|
||||
}
|
||||
|
||||
fn panic_to_object() {
|
||||
panic!("ToObject not yet implemented (Phase 6)")
|
||||
fn panic_to_object() -> ! {
|
||||
panic!("ToObject failed: null or undefined cannot be converted to object")
|
||||
}
|
||||
|
||||
pub fn to_object(val: JsValue, vm: &mut Vm) -> Result<JsValue, &'static str> {
|
||||
if val.is_object() {
|
||||
return Ok(val);
|
||||
}
|
||||
if val.is_null() || val.is_undefined() {
|
||||
return Err("TypeError: Cannot convert null or undefined to object");
|
||||
}
|
||||
let proto_ptr = &*vm.object_prototype as *const JsObject as *mut JsObject;
|
||||
let proto_val = JsValue::from_js_object(proto_ptr);
|
||||
let obj = vm
|
||||
.epoch
|
||||
.alloc(JsObject::new_empty(EMPTY_SHAPE_ID, proto_val));
|
||||
let obj_val = JsValue::from_js_object(obj);
|
||||
let obj_ref = unsafe { &mut *obj };
|
||||
obj_ref.set_inline_prop(0, val);
|
||||
obj_ref.set_prop_count(1);
|
||||
Ok(obj_val)
|
||||
}
|
||||
|
||||
@@ -142,9 +142,28 @@ impl JsObject {
|
||||
self.proto
|
||||
}
|
||||
|
||||
pub fn set_proto(&mut self, proto: JsValue) {
|
||||
pub fn set_proto(&mut self, proto: JsValue) -> Result<(), &'static str> {
|
||||
if proto.is_null() {
|
||||
self.proto = proto;
|
||||
self.generation = self.generation.wrapping_add(1);
|
||||
return Ok(());
|
||||
}
|
||||
if !proto.is_object() {
|
||||
return Err("__proto__ must be an object or null");
|
||||
}
|
||||
let mut cursor = proto;
|
||||
let self_ptr = self as *const JsObject;
|
||||
while cursor.is_object() {
|
||||
let cursor_ptr = cursor.as_js_object_ptr();
|
||||
if cursor_ptr == self_ptr as *mut JsObject {
|
||||
return Err("cyclic __proto__ value");
|
||||
}
|
||||
let obj = unsafe { &*cursor_ptr };
|
||||
cursor = obj.proto;
|
||||
}
|
||||
self.proto = proto;
|
||||
self.generation = self.generation.wrapping_add(1);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn generation(&self) -> u32 {
|
||||
|
||||
+25
-15
@@ -61,6 +61,21 @@ impl Vm {
|
||||
self.string_reverse.get(idx).map(|s| s.as_str())
|
||||
}
|
||||
|
||||
fn resolve_property(&self, obj: &JsObject, prop_name_si: u32) -> Option<JsValue> {
|
||||
if let Some(offset) = shape::lookup_offset(obj.shape_id(), prop_name_si) {
|
||||
return Some(obj.get_prop(offset));
|
||||
}
|
||||
let mut proto = obj.proto();
|
||||
while proto.is_object() {
|
||||
let proto_obj = unsafe { &*proto.as_js_object_ptr() };
|
||||
if let Some(offset) = shape::lookup_offset(proto_obj.shape_id(), prop_name_si) {
|
||||
return Some(proto_obj.get_prop(offset));
|
||||
}
|
||||
proto = proto_obj.proto();
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn run(&mut self, module: &CompiledModule) -> Result<JsValue, String> {
|
||||
self.string_table.clear();
|
||||
self.string_reverse.clear();
|
||||
@@ -265,16 +280,16 @@ impl Vm {
|
||||
|
||||
if cached_shape_id != 0 && cached_shape_id == obj.shape_id() {
|
||||
self.regs[a] = obj.get_prop(cached_offset);
|
||||
} else {
|
||||
if let Some(offset) = shape::lookup_offset(obj.shape_id(), prop_name_si) {
|
||||
} else if let Some(val) = self.resolve_property(obj, prop_name_si) {
|
||||
let offset =
|
||||
shape::lookup_offset(obj.shape_id(), prop_name_si).unwrap_or(0);
|
||||
let new_ext = (obj.shape_id() & 0x00FF_FFFF) | ((offset as u32) << 24);
|
||||
self.bytecode[self.pc - 1] = new_ext;
|
||||
self.regs[a] = obj.get_prop(offset);
|
||||
self.regs[a] = val;
|
||||
} else {
|
||||
self.regs[a] = JsValue::undefined();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OpCode::IC_SET_PROP => {
|
||||
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
|
||||
@@ -316,13 +331,10 @@ impl Vm {
|
||||
}
|
||||
let obj = unsafe { &*obj_ptr };
|
||||
let prop_name_si = self.regs[b].as_string_index();
|
||||
if let Some(offset) = shape::lookup_offset(obj.shape_id(), prop_name_si) {
|
||||
self.regs[a] = obj.get_prop(offset);
|
||||
} else {
|
||||
self.regs[a] = JsValue::undefined();
|
||||
self.regs[a] = self
|
||||
.resolve_property(obj, prop_name_si)
|
||||
.unwrap_or(JsValue::undefined());
|
||||
}
|
||||
}
|
||||
|
||||
OpCode::SET_PROP => {
|
||||
let obj_ptr = self.regs[rd].as_object_ptr() as *mut JsObject;
|
||||
if obj_ptr.is_null() {
|
||||
@@ -353,11 +365,9 @@ impl Vm {
|
||||
return Err("GET_PROP_DYNAMIC key not a string".into());
|
||||
}
|
||||
let prop_name_si = key_val.as_string_index();
|
||||
if let Some(offset) = shape::lookup_offset(obj.shape_id(), prop_name_si) {
|
||||
self.regs[b] = obj.get_prop(offset);
|
||||
} else {
|
||||
self.regs[b] = JsValue::undefined();
|
||||
}
|
||||
self.regs[b] = self
|
||||
.resolve_property(obj, prop_name_si)
|
||||
.unwrap_or(JsValue::undefined());
|
||||
}
|
||||
|
||||
OpCode::SET_PROP_DYNAMIC => {
|
||||
|
||||
Reference in New Issue
Block a user