mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-26 11:41:13 +08:00
types/kernel/vm/builtins: JsString UTF-16 载荷层(FlatU16 变体 + 单元入口)——原 UTF-8 载荷只存 well-formed 串、孤立 surrogate lossy 转 U+FFFD 回写,FromCodePoint/属性转义与字符串面码点语义皆破;现载荷直存 [u64;3](Flat well-formed / FlatU16 单元序列 / Cons 拼接),utf16_len 独立 32 位字,32B 布局锚保持;from_units 智能路由(含孤立→FlatU16),as_str 仅限 Flat,units/units_borrowed 单元借用,as_lossy_str 宽容读;string_forge 编解码 surrogate 感知(孤立 surrogate 逃逸 hex4 编码、解码展开 astral 代理对、string_ptr 由单元物化);VmHost 单元物化/分配/查询入口 + runtime_api 单元 API;字符串内置全法单元化(charAt/slice/substr/split/replace/search/match/matchAll 单元定位;空模式边界:search→0、match→[""]、replace 插 0 位、matchAll 游标耗尽守卫;接收者 ToString 错误原样传播);正则内置单元化(exec/test/search/symbol_* 单元文本,替换串 \u{...} 与孤立 surrogate 文本处理,lastIndex 与 matchAll 游标单元化);字符串迭代器码点化(高代理+后续低代理成对产出,astral 值回真实码点);String(Symbol) 抛 TypeError;回归钉更新五处(charAt/split/slice/substr 单元精确语义 + dispose 钉改 TypeError 断言);四 crate 全绿(oxide_vm 98 套件 2403 测)+ clippy/fmt 零新增
This commit is contained in:
@@ -528,9 +528,9 @@ fn symbol_dispose_and_async_dispose_registered() {
|
||||
let result = eval(&mut vm, src).unwrap();
|
||||
assert_eq!(result.as_bool(), expected, "for {}", src);
|
||||
}
|
||||
// 描述性名称经 String 构造器反射(well_known_symbol_name 表)。
|
||||
let desc = eval(&mut vm, "String(Symbol.dispose)").unwrap();
|
||||
assert_eq!(to_str(&vm, desc), "Symbol(Symbol.dispose)");
|
||||
// ToString(Symbol) 按规格抛 TypeError(String 构造器无描述性名称通道)。
|
||||
let err = eval(&mut vm, "try { String(Symbol.dispose); 'no-throw' } catch (e) { e.name }").unwrap();
|
||||
assert_eq!(to_str(&vm, err), "TypeError");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -940,25 +940,45 @@ fn string_methods_null_receiver_throw_type_error() {
|
||||
#[test]
|
||||
fn string_slice_astral_character_indices() {
|
||||
// UTF-16 单元索引语义:astral 字符占 2 单元,切片边界落在代理对中间时
|
||||
// 保留所在 astral 字符(孤立代理无法在 UTF-8 表示,见架构限制)。
|
||||
// 单元原样保留(单元载荷可承载孤立 surrogate,规格口径)。
|
||||
let mut vm = Vm::new();
|
||||
let s = eval(&mut vm, "'\\u{1F600}ab'.slice(1, 3)").unwrap();
|
||||
assert_eq!(to_str(&vm, s), "\u{1F600}a");
|
||||
let s = eval(&mut vm, "'\\u{1F600}ab'.slice(0, 1)").unwrap();
|
||||
assert_eq!(to_str(&vm, s), "\u{1F600}");
|
||||
let r = eval(
|
||||
&mut vm,
|
||||
"var s = '\\u{1F600}ab'.slice(1, 3); s.length === 2 && s.charCodeAt(0) === 0xDE00 && s.charCodeAt(1) === 0x61",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(r.as_bool());
|
||||
let r = eval(
|
||||
&mut vm,
|
||||
"var s = '\\u{1F600}ab'.slice(0, 1); s.length === 1 && s.charCodeAt(0) === 0xD83D",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(r.as_bool());
|
||||
let s = eval(&mut vm, "'\\u{1F600}'.padStart(3, 'x')").unwrap();
|
||||
assert_eq!(to_str(&vm, s), "xx\u{1F600}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn string_char_at_ascii_and_astral() {
|
||||
// charAt 产出:ASCII 走单字符缓存,astral 按 UTF-16 单元定位(落在代理对
|
||||
// 中间时返回所在 astral 字符,架构限制),越界空串,缺省参数取首字符。
|
||||
// charAt 按码元定位:单单元子串(代理对各出 1 单元,规格口径——
|
||||
// 规格返回单元子串而非 Unicode 标量),越界空串,缺省参数取首字符。
|
||||
let mut vm = Vm::new();
|
||||
let s = eval(&mut vm, "'abc'.charAt(1)").unwrap();
|
||||
assert_eq!(to_str(&vm, s), "b");
|
||||
let s = eval(&mut vm, "'\\u{1F600}ab'.charAt(0)").unwrap();
|
||||
assert_eq!(to_str(&vm, s), "\u{1F600}");
|
||||
let r = eval(
|
||||
&mut vm,
|
||||
"'\\u{1F600}ab'.charAt(0).length === 1 && '\\u{1F600}ab'.charAt(0).charCodeAt(0) === 0xD83D",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(r.as_bool());
|
||||
let r = eval(
|
||||
&mut vm,
|
||||
"'\\u{1F600}ab'.charAt(1).length === 1 && '\\u{1F600}ab'.charAt(1).charCodeAt(0) === 0xDE00",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(r.as_bool());
|
||||
let r = eval(&mut vm, "'\\u{1F600}ab'.charAt(2) === 'a'").unwrap();
|
||||
assert!(r.as_bool());
|
||||
let s = eval(&mut vm, "'ab'.charAt(5)").unwrap();
|
||||
assert_eq!(to_str(&vm, s), "");
|
||||
let s = eval(&mut vm, "'xy'.charAt()").unwrap();
|
||||
@@ -975,13 +995,16 @@ fn string_char_at_eq_perm_string() {
|
||||
|
||||
#[test]
|
||||
fn string_split_empty_separator_chars() {
|
||||
// 空分隔 split 逐字符产出:ASCII 走单字符缓存,混合 astral 按标量切分。
|
||||
// 空分隔 split 逐码元产出:ASCII 走单字符缓存,代理对各出 1 单元元素
|
||||
// (规格口径:空分隔按单元切分,孤立 surrogate 各为独立元素)。
|
||||
let mut vm = Vm::new();
|
||||
let s = eval(&mut vm, "'abc'.split('').join('-')").unwrap();
|
||||
assert_eq!(to_str(&vm, s), "a-b-c");
|
||||
let result = eval(&mut vm, "'\\u{1F600}a'.split('').length").unwrap();
|
||||
assert_eq!(result.as_int(), 2);
|
||||
let result = eval(&mut vm, "'\\u{1F600}a'.split('')[1]").unwrap();
|
||||
assert_eq!(result.as_int(), 3);
|
||||
let r = eval(&mut vm, "'\\u{1F600}a'.split('')[1].charCodeAt(0) === 0xDE00").unwrap();
|
||||
assert!(r.as_bool());
|
||||
let result = eval(&mut vm, "'\\u{1F600}a'.split('')[2]").unwrap();
|
||||
assert_eq!(to_str(&vm, result), "a");
|
||||
}
|
||||
|
||||
@@ -1016,10 +1039,17 @@ fn string_utf16_length_char_at_code_at() {
|
||||
assert_eq!(r.as_int(), 0xDE00);
|
||||
let r = eval(&mut vm, "'\\u{1F600}a'.charCodeAt(2)").unwrap();
|
||||
assert_eq!(r.as_int(), 0x61);
|
||||
let r = eval(&mut vm, "'\\u{1F600}ab'.charAt(2)").unwrap();
|
||||
assert_eq!(to_str(&vm, r), "a");
|
||||
let r = eval(&mut vm, "'\\u{1F600}ab'.charAt(1)").unwrap();
|
||||
assert_eq!(to_str(&vm, r), "\u{1F600}");
|
||||
let r = eval(&mut vm, "'\\u{1F600}ab'.charAt(2) === 'a'").unwrap();
|
||||
assert!(r.as_bool());
|
||||
// charAt 出单单元子串:代理对位置各出 1 单元(高/低 surrogate)。
|
||||
let r = eval(
|
||||
&mut vm,
|
||||
"'\\u{1F600}ab'.charAt(0).length === 1 && '\\u{1F600}ab'.charAt(0).charCodeAt(0) === 0xD83D",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(r.as_bool());
|
||||
let r = eval(&mut vm, "'\\u{1F600}ab'.charAt(1).charCodeAt(0) === 0xDE00").unwrap();
|
||||
assert!(r.as_bool());
|
||||
let r = eval(&mut vm, "'\\u{1F600}ab'.charAt(4)").unwrap();
|
||||
assert_eq!(to_str(&vm, r), "");
|
||||
}
|
||||
@@ -1040,7 +1070,8 @@ fn string_utf16_at() {
|
||||
|
||||
#[test]
|
||||
fn string_utf16_slice_substring_substr() {
|
||||
// 切片族按 UTF-16 单元计数:边界落在代理对中间时保留所在 astral 字符。
|
||||
// 切片族按 UTF-16 单元计数:边界落在代理对中间时单元原样保留(孤立
|
||||
// surrogate 由单元载荷承载,规格口径)。
|
||||
let mut vm = Vm::new();
|
||||
let s = eval(&mut vm, "'\\u{1F600}ab'.slice(2)").unwrap();
|
||||
assert_eq!(to_str(&vm, s), "ab");
|
||||
@@ -1054,8 +1085,12 @@ fn string_utf16_slice_substring_substr() {
|
||||
assert_eq!(to_str(&vm, s), "\u{1F600}");
|
||||
let s = eval(&mut vm, "'\\u{1F600}ab'.substr(2, 2)").unwrap();
|
||||
assert_eq!(to_str(&vm, s), "ab");
|
||||
let s = eval(&mut vm, "'\\u{1F600}ab'.substr(1, 2)").unwrap();
|
||||
assert_eq!(to_str(&vm, s), "\u{1F600}a");
|
||||
let r = eval(
|
||||
&mut vm,
|
||||
"var s = '\\u{1F600}ab'.substr(1, 2); s.length === 2 && s.charCodeAt(0) === 0xDE00 && s.charCodeAt(1) === 0x61",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(r.as_bool());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user