mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-26 03:31:12 +08:00
fix: 删 exec 尾部 lastIndex 重复写回并修正 flags 注释
This commit is contained in:
@@ -541,8 +541,8 @@ pub fn clone_regexp_native(old_obj: &JsObject, new_obj: &mut JsObject) {
|
|||||||
///
|
///
|
||||||
/// # 步骤
|
/// # 步骤
|
||||||
/// 1. this 须为 RegExp 实例(内部槽门禁,非对象/非 RegExp 抛 TypeError)。
|
/// 1. this 须为 RegExp 实例(内部槽门禁,非对象/非 RegExp 抛 TypeError)。
|
||||||
/// 2. S = ToString(string);flags 串判 global/sticky(sticky 时 global 归
|
/// 2. S = ToString(string);flags 串判 global/sticky(g/y 字面量互斥,至多
|
||||||
/// false 的效果体现为两者只影响同一分支)。
|
/// 其一,共用 tracks 分支)。
|
||||||
/// 3. 共享搜索核(与 exec 同一实现):lastIndex 读、越界短路、sticky 锚定
|
/// 3. 共享搜索核(与 exec 同一实现):lastIndex 读、越界短路、sticky 锚定
|
||||||
/// 过滤、lastIndex Set 写回。
|
/// 过滤、lastIndex Set 写回。
|
||||||
/// 4. 命中返回 true,否则 false。
|
/// 4. 命中返回 true,否则 false。
|
||||||
@@ -593,7 +593,7 @@ pub fn regexp_test<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// exec/test 共享搜索核(规范 RegExpBuiltinExec 的搜索部分):lastIndex 经
|
/// exec/test 共享搜索核(规范 RegExpBuiltinExec 的搜索部分):lastIndex 经
|
||||||
/// Get + ToLength 读取,搜索起点(global/sticky 取 lastIndex、其余取 0),
|
/// Get + ToLength 无条件读取(非 global/sticky 臂读到后丢弃、起点恒 0),
|
||||||
/// 越界短路(先 Set 0),匹配与 sticky 后置锚定过滤,lastIndex Set 写回
|
/// 越界短路(先 Set 0),匹配与 sticky 后置锚定过滤,lastIndex Set 写回
|
||||||
/// (失败置 0、成功置匹配末尾,仅 global/sticky,非可写属性抛 TypeError)。
|
/// (失败置 0、成功置匹配末尾,仅 global/sticky,非可写属性抛 TypeError)。
|
||||||
///
|
///
|
||||||
@@ -607,7 +607,8 @@ fn rx_search<H: VmHost>(
|
|||||||
vm: &mut H, re_ptr: *mut JsObject, this_val: JsValue, regex: ®ress::Regex, text: &MatchText,
|
vm: &mut H, re_ptr: *mut JsObject, this_val: JsValue, regex: ®ress::Regex, text: &MatchText,
|
||||||
tracks_last_index: bool, is_sticky: bool,
|
tracks_last_index: bool, is_sticky: bool,
|
||||||
) -> Result<Option<regress::Match>, JsValue> {
|
) -> Result<Option<regress::Match>, JsValue> {
|
||||||
// lastIndex 读走 Get + ToLength:完整属性解析,读异常传播原异常。
|
// lastIndex 读无条件执行(规范先读后在非 global/sticky 臂丢弃);
|
||||||
|
// 读走 Get + ToLength:完整属性解析,读异常传播原异常。
|
||||||
let last_index = {
|
let last_index = {
|
||||||
let li_si = vm.kernel_core().perm_interner().intern("lastIndex").0;
|
let li_si = vm.kernel_core().perm_interner().intern("lastIndex").0;
|
||||||
match vm.ordinary_get(unsafe { &*re_ptr }, li_si, this_val) {
|
match vm.ordinary_get(unsafe { &*re_ptr }, li_si, this_val) {
|
||||||
@@ -636,7 +637,7 @@ fn rx_search<H: VmHost>(
|
|||||||
// 过滤——底层引擎对 y 不原生锚定,命中起点须恰在 lastIndex 才算有效。
|
// 过滤——底层引擎对 y 不原生锚定,命中起点须恰在 lastIndex 才算有效。
|
||||||
let match_result = text.find_from_units(regex, start);
|
let match_result = text.find_from_units(regex, start);
|
||||||
let anchored = if is_sticky {
|
let anchored = if is_sticky {
|
||||||
match_result.filter(|m| text.unit_pos(m.range().start) == last_index)
|
match_result.filter(|m| text.unit_pos(m.range().start) == start)
|
||||||
} else {
|
} else {
|
||||||
match_result
|
match_result
|
||||||
};
|
};
|
||||||
@@ -662,8 +663,8 @@ fn rx_search<H: VmHost>(
|
|||||||
/// # 步骤
|
/// # 步骤
|
||||||
/// 1. this 仅需对象(IsObject 门禁);编译正则槽必须存在,非 RegExp 对象无
|
/// 1. this 仅需对象(IsObject 门禁);编译正则槽必须存在,非 RegExp 对象无
|
||||||
/// 可匹配模式,同抛 TypeError。
|
/// 可匹配模式,同抛 TypeError。
|
||||||
/// 2. S = ToString(string);flags 串判 global/sticky(sticky 时 global 归 false
|
/// 2. S = ToString(string);flags 串判 global/sticky(g/y 字面量互斥,至多
|
||||||
/// 的效果体现为两者只影响同一分支)。
|
/// 其一,共用 tracks 分支)。
|
||||||
/// 3. 共享搜索核(与 test 同一实现):lastIndex 读(Get + ToLength)、越界
|
/// 3. 共享搜索核(与 test 同一实现):lastIndex 读(Get + ToLength)、越界
|
||||||
/// 短路(先 Set 0)、sticky 后置锚定过滤、lastIndex Set 写回。
|
/// 短路(先 Set 0)、sticky 后置锚定过滤、lastIndex Set 写回。
|
||||||
/// 4. 无匹配回 null;命中构建结果数组(捕获组、index、input、groups)。
|
/// 4. 无匹配回 null;命中构建结果数组(捕获组、index、input、groups)。
|
||||||
@@ -752,13 +753,6 @@ pub fn regexp_exec<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
|||||||
vm.set_or_create_prop_value(unsafe { &mut *arr }, indices_si, indices_val);
|
vm.set_or_create_prop_value(unsafe { &mut *arr }, indices_si, indices_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 成功:lastIndex 推进到匹配末尾(仅 global/sticky),Set 语义。
|
|
||||||
if tracks_last_index {
|
|
||||||
if let Err(err) = set_last_index(vm, re_ptr, this_val, text.unit_pos(range.end)) {
|
|
||||||
return NativeResult::Err(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NativeResult::Ok(JsValue::from_js_object(arr))
|
NativeResult::Ok(JsValue::from_js_object(arr))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -265,6 +265,15 @@ fn regexp_exec_negative_last_index_clamped_to_zero() {
|
|||||||
assert_eq!(to_str(&vm, result), "0:1");
|
assert_eq!(to_str(&vm, result), "0:1");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn regexp_exec_last_index_set_once_on_success() {
|
||||||
|
// 成功路径 lastIndex 恰好 Set 一次(写回在核内单点):计数 setter 只被观察一次。
|
||||||
|
let source = "(() => { var re = /a/g; var n = 0; Object.defineProperty(re, 'lastIndex', { configurable: true, set() { n += 1; }, get() { return 0; } }); re.exec('a'); return String(n); })()";
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
let result = eval(&mut vm, source).unwrap();
|
||||||
|
assert_eq!(to_str(&vm, result), "1");
|
||||||
|
}
|
||||||
|
|
||||||
// --- test() lastIndex 规范语义(sticky 锚定 / 越界短路 / 不追踪不写回)---
|
// --- test() lastIndex 规范语义(sticky 锚定 / 越界短路 / 不追踪不写回)---
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Reference in New Issue
Block a user