feat: 搭建 Iterator 与 for-of 语法基础设施

This commit is contained in:
爱特每羊队
2026-06-08 13:48:54 +08:00
parent 4d60491e0e
commit 3880882fda
12 changed files with 246 additions and 4 deletions
+2 -2
View File
@@ -24,8 +24,8 @@ pub fn bind_object(kernel: &Arc<OxideKernel>, global: &mut JsObject) {
from_entries: crate::builtins::object::object_from_entries as *const (),
get_prototype_of: crate::builtins::object::object_get_prototype_of as *const (),
has_own: crate::builtins::object::object_has_own as *const (),
entries: std::ptr::null(),
values: std::ptr::null(),
entries: crate::builtins::object::object_entries as *const (),
values: crate::builtins::object::object_values as *const (),
};
kernel.builtin_world().bind_object_methods(
&methods,
+2 -2
View File
@@ -30,8 +30,8 @@ pub fn bind_string(kernel: &Arc<OxideKernel>, global: &mut JsObject) {
trim_end: crate::builtins::string::string_trim_end as *const (),
code_point_at: crate::builtins::string::string_code_point_at as *const (),
normalize: crate::builtins::string::string_normalize as *const (),
match_all: std::ptr::null(),
replace_all: std::ptr::null(),
match_all: crate::builtins::string::string_match_all as *const (),
replace_all: crate::builtins::string::string_replace_all as *const (),
};
kernel.builtin_world().bind_string_methods(
&string_methods,
@@ -45,6 +45,11 @@ pub fn bind_symbol(kernel: &Arc<OxideKernel>, global: &mut JsObject) {
);
bind_well_known_symbol(kernel, ctor, sf, sh, "split", sym_split_val);
let sym_iterator_val = JsValue::from_js_object(
kernel.builtin_world().sym_iterator.as_ptr() as *mut JsObject,
);
bind_well_known_symbol(kernel, ctor, sf, sh, "iterator", sym_iterator_val);
bind_constructor_hash!(
kernel,
global,
+37
View File
@@ -379,3 +379,40 @@ pub fn object_has_own(vm: &mut Vm, args: &[u8]) -> NativeResult {
if !key_val.is_string() { return Ok(JsValue::bool(false)); }
Ok(JsValue::bool(false))
}
pub fn object_entries(vm: &mut Vm, args: &[u8]) -> NativeResult {
let obj_ptr = require_obj_arg(vm, args, "entries")?;
let obj = unsafe { &*obj_ptr };
let keys = walk_own_keys(vm, obj);
let n = keys.len().min(255);
let array_proto = vm.kernel().builtin_world().array_proto.as_ptr() as *mut JsObject;
let arr = vm.epoch().alloc(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(array_proto), n, vm.epoch().bump()));
for (_i, (si, offset)) in keys.iter().enumerate().take(n) {
let key_str = vm.kernel().string_forge().lookup(*si).unwrap_or_default();
let key_val = vm.intern(&key_str);
let val = obj.get_prop_at(*offset);
let pair = vm.epoch().alloc(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(array_proto), 2, vm.epoch().bump()));
unsafe {
(*pair).set_prop_at(0, key_val);
(*pair).set_prop_at(1, val);
(*pair).set_prop_count(2);
(*arr).ensure_hash_props().push(Box::new(JsValue::from_js_object(pair)));
}
}
Ok(JsValue::from_js_object(arr))
}
pub fn object_values(vm: &mut Vm, args: &[u8]) -> NativeResult {
let obj_ptr = require_obj_arg(vm, args, "values")?;
let obj = unsafe { &*obj_ptr };
let keys = walk_own_keys(vm, obj);
let n = keys.len().min(255);
let array_proto = vm.kernel().builtin_world().array_proto.as_ptr() as *mut JsObject;
let arr = vm.epoch().alloc(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(array_proto), n, vm.epoch().bump()));
for (i, (_si, offset)) in keys.iter().enumerate().take(n) {
let val = obj.get_prop_at(*offset);
unsafe { (*arr).set_prop_at(i as u8, val); }
}
unsafe { (*arr).set_prop_count(n as u8); }
Ok(JsValue::from_js_object(arr))
}
+33
View File
@@ -469,3 +469,36 @@ pub fn string_normalize(vm: &mut Vm, args: &[u8]) -> NativeResult {
};
Ok(vm.intern(&result))
}
pub fn string_match_all(vm: &mut Vm, args: &[u8]) -> NativeResult {
let s = this_string(vm, args);
if args.len() < 2 { return Err(JsValue::undefined()); }
let pattern_val = vm.reg(args[1]);
if is_regexp_obj(pattern_val, vm) {
let re_ptr = pattern_val.as_js_object_ptr();
let re = unsafe { &*re_ptr };
let fn_ptr = match re.native_fn() { Some(p) => p, None => return Ok(JsValue::undefined()) };
let regex = unsafe { &*(fn_ptr as *const regex::Regex) };
let matches: Vec<String> = regex.find_iter(&s).map(|m| m.as_str().to_string()).collect();
return Ok(make_string_array(vm, &matches));
}
Ok(JsValue::undefined())
}
pub fn string_replace_all(vm: &mut Vm, args: &[u8]) -> NativeResult {
let s = this_string(vm, args);
if args.len() < 2 { return Ok(vm.intern(&s)); }
let pattern_val = vm.reg(args[1]);
let replacement = if args.len() > 2 { as_string(vm, vm.reg(args[2])) } else { String::new() };
if is_regexp_obj(pattern_val, vm) {
let re_ptr = pattern_val.as_js_object_ptr();
let re = unsafe { &*re_ptr };
let fn_ptr = match re.native_fn() { Some(p) => p, None => return Ok(vm.intern(&s)) };
let regex = unsafe { &*(fn_ptr as *const regex::Regex) };
let result = regex.replace_all(&s, replacement.as_str()).to_string();
return Ok(vm.intern(&result));
}
let pattern = as_string(vm, pattern_val);
let result = s.replace(&pattern, &replacement);
Ok(vm.intern(&result))
}
+12
View File
@@ -174,6 +174,8 @@ pub struct Vm {
pub(crate) pending_error_kind: Option<&'static str>,
pub(crate) symbol_counter: u32,
pub(crate) symbol_descriptions: Vec<String>,
#[allow(dead_code)]
pub(crate) for_of_iters: Vec<*mut u8>,
}
impl Vm {
@@ -203,6 +205,7 @@ impl Vm {
pending_error_kind: None,
symbol_counter: 0,
symbol_descriptions: Vec::new(),
for_of_iters: Vec::new(),
}
}
@@ -230,6 +233,7 @@ impl Vm {
pending_error_kind: None,
symbol_counter: 0,
symbol_descriptions: Vec::new(),
for_of_iters: Vec::new(),
}
}
@@ -1573,6 +1577,14 @@ impl Vm {
self.for_in_iters.pop();
}
OpCode::FOR_OF_INIT => {}
OpCode::FOR_OF_NEXT => {},
OpCode::FOR_OF_DONE => {},
OpCode::FOR_OF_CLOSE => {},
OpCode::THROW => {
let exc_value = self.regs[rd];
self.exception_value = Some(exc_value);