mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
fix: 正则 v 标志零宽推进按码点口径
This commit is contained in:
@@ -1094,14 +1094,14 @@ pub(crate) fn replacement_units<H: VmHost>(vm: &mut H, val: JsValue) -> Result<V
|
|||||||
///
|
///
|
||||||
/// # 步骤
|
/// # 步骤
|
||||||
/// 1. this 仅需对象(IsObject 门禁)。
|
/// 1. this 仅需对象(IsObject 门禁)。
|
||||||
/// 2. S = ToString(string);flags/global/unicode 经 Get live 直读(unicode 读
|
/// 2. S = ToString(string);flags/global/unicode/unicodeSets 经 Get live 直读
|
||||||
/// 无条件先于非 global 返回,读序与规范一致)。
|
/// (unicode 读无条件先于非 global 返回,读序与规范一致)。
|
||||||
/// 3. 非 global:返回共享 exec(GetMethod + Call)结果原值。
|
/// 3. 非 global:返回共享 exec(GetMethod + Call)结果原值。
|
||||||
/// 4. global:ToIntegerOrInfinity(Get "lastIndex") 副作用读后 Set 0,再经共享
|
/// 4. global:ToIntegerOrInfinity(Get "lastIndex") 副作用读后 Set 0,再经共享
|
||||||
/// exec 循环逐匹配收集;零宽匹配按 fullUnicode 口径推进 lastIndex。
|
/// exec 循环逐匹配收集;零宽匹配按 fullUnicode 口径推进 lastIndex。
|
||||||
///
|
///
|
||||||
/// # 边界与前提
|
/// # 边界与前提
|
||||||
/// - 各属性读(flags/global/unicode/lastIndex/结果属性)均传播原异常。
|
/// - 各属性读(flags/global/unicode/unicodeSets/lastIndex/结果属性)均传播原异常。
|
||||||
/// - exec 结果须为 null 或对象,否则 TypeError。
|
/// - exec 结果须为 null 或对象,否则 TypeError。
|
||||||
///
|
///
|
||||||
/// # 副作用
|
/// # 副作用
|
||||||
@@ -1128,10 +1128,17 @@ pub fn regexp_symbol_match<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
|||||||
Ok(g) => g,
|
Ok(g) => g,
|
||||||
Err(err) => return NativeResult::Err(err),
|
Err(err) => return NativeResult::Err(err),
|
||||||
};
|
};
|
||||||
|
// fullUnicode = u 或 v 标志任一为真(规范 "If flags contains 'u' or flags
|
||||||
|
// contains 'v'"),两属性 live 读取后或。
|
||||||
let full_unicode = match rx_get_bool_prop(vm, re_ptr, "unicode", this_val) {
|
let full_unicode = match rx_get_bool_prop(vm, re_ptr, "unicode", this_val) {
|
||||||
Ok(u) => u,
|
Ok(u) => u,
|
||||||
Err(err) => return NativeResult::Err(err),
|
Err(err) => return NativeResult::Err(err),
|
||||||
};
|
};
|
||||||
|
let full_unicode = full_unicode
|
||||||
|
|| match rx_get_bool_prop(vm, re_ptr, "unicodeSets", this_val) {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(err) => return NativeResult::Err(err),
|
||||||
|
};
|
||||||
|
|
||||||
if !is_global {
|
if !is_global {
|
||||||
let result = match regexp_exec_call(vm, re_ptr, this_val, s_val) {
|
let result = match regexp_exec_call(vm, re_ptr, this_val, s_val) {
|
||||||
@@ -1203,7 +1210,7 @@ pub fn regexp_symbol_match<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
|||||||
/// # 步骤
|
/// # 步骤
|
||||||
/// 1. this 仅需对象(IsObject 门禁);S = ToString(string)。
|
/// 1. this 仅需对象(IsObject 门禁);S = ToString(string)。
|
||||||
/// 2. 非函数分支先 ToString(replacement)(Symbol 抛 TypeError)。
|
/// 2. 非函数分支先 ToString(replacement)(Symbol 抛 TypeError)。
|
||||||
/// 3. flags/global/unicode 经 Get live 直读;global 时
|
/// 3. flags/global/unicode/unicodeSets 经 Get live 直读;global 时
|
||||||
/// ToIntegerOrInfinity(Get "lastIndex") 副作用读后 Set 0。
|
/// ToIntegerOrInfinity(Get "lastIndex") 副作用读后 Set 0。
|
||||||
/// 4. 替换体(regexp_replace_results):exec 循环收集结果(零宽匹配按
|
/// 4. 替换体(regexp_replace_results):exec 循环收集结果(零宽匹配按
|
||||||
/// fullUnicode 口径推进 lastIndex),按结果属性逐条展开
|
/// fullUnicode 口径推进 lastIndex),按结果属性逐条展开
|
||||||
@@ -1211,7 +1218,7 @@ pub fn regexp_symbol_match<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
|||||||
/// position 越上界钳到串长,乱序(position 回退)的替换被忽略。
|
/// position 越上界钳到串长,乱序(position 回退)的替换被忽略。
|
||||||
///
|
///
|
||||||
/// # 边界与前提
|
/// # 边界与前提
|
||||||
/// - 各属性读(flags/global/unicode/lastIndex/结果属性)均传播原异常。
|
/// - 各属性读(flags/global/unicode/unicodeSets/lastIndex/结果属性)均传播原异常。
|
||||||
/// - exec 结果须为 null 或对象,否则 TypeError。
|
/// - exec 结果须为 null 或对象,否则 TypeError。
|
||||||
///
|
///
|
||||||
/// # 副作用
|
/// # 副作用
|
||||||
@@ -1290,7 +1297,10 @@ pub(crate) fn regexp_replace_results<H: VmHost>(
|
|||||||
is_global: bool,
|
is_global: bool,
|
||||||
) -> Result<Vec<u16>, JsValue> {
|
) -> Result<Vec<u16>, JsValue> {
|
||||||
let length_s = units.len();
|
let length_s = units.len();
|
||||||
let full_unicode = rx_get_bool_prop(vm, re_ptr, "unicode", this_val)?;
|
// fullUnicode = u 或 v 标志任一为真(规范 "If flags contains 'u' or flags
|
||||||
|
// contains 'v'"),两属性 live 读取后或。
|
||||||
|
let full_unicode =
|
||||||
|
rx_get_bool_prop(vm, re_ptr, "unicode", this_val)? || rx_get_bool_prop(vm, re_ptr, "unicodeSets", this_val)?;
|
||||||
|
|
||||||
// exec 循环:global 收集到 null 为止,非 global 至多一条。
|
// exec 循环:global 收集到 null 为止,非 global 至多一条。
|
||||||
let mut results: Vec<JsValue> = Vec::new();
|
let mut results: Vec<JsValue> = Vec::new();
|
||||||
@@ -1647,7 +1657,7 @@ pub fn regexp_symbol_split<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
|||||||
Ok(f) => f,
|
Ok(f) => f,
|
||||||
Err(err) => return NativeResult::Err(err),
|
Err(err) => return NativeResult::Err(err),
|
||||||
};
|
};
|
||||||
let unicode_matching = flags.contains('u');
|
let unicode_matching = flags.contains('u') || flags.contains('v');
|
||||||
let new_flags = if flags.contains('y') { flags } else { format!("{flags}y") };
|
let new_flags = if flags.contains('y') { flags } else { format!("{flags}y") };
|
||||||
let new_flags_val = vm.new_string_owned(new_flags);
|
let new_flags_val = vm.new_string_owned(new_flags);
|
||||||
let splitter_val = match vm.construct_ctor(c, &[this_val, new_flags_val]) {
|
let splitter_val = match vm.construct_ctor(c, &[this_val, new_flags_val]) {
|
||||||
|
|||||||
@@ -1168,3 +1168,23 @@ fn regexp_replace_results_groups_to_object_and_receiver() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(to_str(&vm, result), "E");
|
assert_eq!(to_str(&vm, result), "E");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn regexp_v_flag_zero_width_surrogate_pair_match_returns() {
|
||||||
|
// 回归钉:v 标志零宽正则对含代理对串必须返回匹配(零宽推进按码点口径,
|
||||||
|
// 与 exec 起点钳制自洽),不无限循环;replace/split 同族同口径。
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
let result = eval(&mut vm, "var m = '𠮷a'.match(/(?:)/gv); m.length + ':' + m.join('|')").unwrap();
|
||||||
|
assert_eq!(to_str(&vm, result), "3:||");
|
||||||
|
let result = eval(&mut vm, "'𠮷a'.replace(/(?:)/gv, 'x')").unwrap();
|
||||||
|
assert_eq!(to_str(&vm, result), "x𠮷xax");
|
||||||
|
let result = eval(&mut vm, "var m = '𠮷a'.split(/(?:)/gv); m.length + ':' + m.join('|')").unwrap();
|
||||||
|
assert_eq!(to_str(&vm, result), "2:𠮷|a");
|
||||||
|
let result = eval(&mut vm, "var m = /(?:)/gv.exec('𠮷a'); m.length + ':' + m[0].length").unwrap();
|
||||||
|
assert_eq!(to_str(&vm, result), "1:0");
|
||||||
|
// u 标志与无标志面零回归(同串同零宽模式)。
|
||||||
|
let result = eval(&mut vm, "var m = '𠮷a'.match(/(?:)/gu); m.length + ':' + m.join('|')").unwrap();
|
||||||
|
assert_eq!(to_str(&vm, result), "3:||");
|
||||||
|
let result = eval(&mut vm, "var m = '𠮷a'.match(/(?:)/g); m.length + ':' + m.join('|')").unwrap();
|
||||||
|
assert_eq!(to_str(&vm, result), "4:|||");
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user