mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 20:17:44 +00:00
LibJS: Report string properties using UTF-16 code units
String length is reported as the number of UTF-16 code units, and string indices are reported as the UTF-16 code units themselves.
This commit is contained in:
parent
0c42aece36
commit
2bba20d123
2 changed files with 33 additions and 7 deletions
|
@ -5,7 +5,7 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <AK/Utf8View.h>
|
#include <AK/Utf16View.h>
|
||||||
#include <LibJS/Runtime/AbstractOperations.h>
|
#include <LibJS/Runtime/AbstractOperations.h>
|
||||||
#include <LibJS/Runtime/GlobalObject.h>
|
#include <LibJS/Runtime/GlobalObject.h>
|
||||||
#include <LibJS/Runtime/PrimitiveString.h>
|
#include <LibJS/Runtime/PrimitiveString.h>
|
||||||
|
@ -34,7 +34,7 @@ void StringObject::initialize(GlobalObject& global_object)
|
||||||
{
|
{
|
||||||
auto& vm = this->vm();
|
auto& vm = this->vm();
|
||||||
Object::initialize(global_object);
|
Object::initialize(global_object);
|
||||||
define_direct_property(vm.names.length, Value(Utf8View(m_string.string()).length()), 0);
|
define_direct_property(vm.names.length, Value(m_string.utf16_string_view().length_in_code_units()), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StringObject::visit_edges(Cell::Visitor& visitor)
|
void StringObject::visit_edges(Cell::Visitor& visitor)
|
||||||
|
@ -70,17 +70,17 @@ static Optional<PropertyDescriptor> string_get_own_property(GlobalObject& global
|
||||||
|
|
||||||
// 8. Let str be S.[[StringData]].
|
// 8. Let str be S.[[StringData]].
|
||||||
// 9. Assert: Type(str) is String.
|
// 9. Assert: Type(str) is String.
|
||||||
auto& str = string.primitive_string().string();
|
auto str = string.primitive_string().utf16_string_view();
|
||||||
|
|
||||||
// 10. Let len be the length of str.
|
// 10. Let len be the length of str.
|
||||||
auto length = str.length();
|
auto length = str.length_in_code_units();
|
||||||
|
|
||||||
// 11. If ℝ(index) < 0 or len ≤ ℝ(index), return undefined.
|
// 11. If ℝ(index) < 0 or len ≤ ℝ(index), return undefined.
|
||||||
if (index.as_double() < 0 || length <= index.as_double())
|
if (index.as_double() < 0 || length <= index.as_double())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
// 12. Let resultStr be the String value of length 1, containing one code unit from str, specifically the code unit at index ℝ(index).
|
// 12. Let resultStr be the String value of length 1, containing one code unit from str, specifically the code unit at index ℝ(index).
|
||||||
auto result_str = js_string(string.vm(), str.substring(index.as_double(), 1));
|
auto result_str = js_string(string.vm(), str.substring_view(index.as_double(), 1));
|
||||||
|
|
||||||
// 13. Return the PropertyDescriptor { [[Value]]: resultStr, [[Writable]]: false, [[Enumerable]]: true, [[Configurable]]: false }.
|
// 13. Return the PropertyDescriptor { [[Value]]: resultStr, [[Writable]]: false, [[Enumerable]]: true, [[Configurable]]: false }.
|
||||||
return PropertyDescriptor {
|
return PropertyDescriptor {
|
||||||
|
@ -138,12 +138,12 @@ MarkedValueList StringObject::internal_own_property_keys() const
|
||||||
auto keys = MarkedValueList { heap() };
|
auto keys = MarkedValueList { heap() };
|
||||||
|
|
||||||
// 2. Let str be O.[[StringData]].
|
// 2. Let str be O.[[StringData]].
|
||||||
auto& str = m_string.string();
|
auto str = m_string.utf16_string_view();
|
||||||
|
|
||||||
// 3. Assert: Type(str) is String.
|
// 3. Assert: Type(str) is String.
|
||||||
|
|
||||||
// 4. Let len be the length of str.
|
// 4. Let len be the length of str.
|
||||||
auto length = str.length();
|
auto length = str.length_in_code_units();
|
||||||
|
|
||||||
// 5. For each integer i starting with 0 such that i < len, in ascending order, do
|
// 5. For each integer i starting with 0 such that i < len, in ascending order, do
|
||||||
for (size_t i = 0; i < length; ++i) {
|
for (size_t i = 0; i < length; ++i) {
|
||||||
|
|
|
@ -13,4 +13,30 @@ test("length", () => {
|
||||||
expect(new String("a").length).toBe(1);
|
expect(new String("a").length).toBe(1);
|
||||||
expect(new String("\u180E").length).toBe(1);
|
expect(new String("\u180E").length).toBe(1);
|
||||||
expect(new String("\uDBFF\uDFFF").length).toBe(2);
|
expect(new String("\uDBFF\uDFFF").length).toBe(2);
|
||||||
|
|
||||||
|
// Issue #2280
|
||||||
|
expect("⛳".length).toBe(1);
|
||||||
|
expect("🔥".length).toBe(2);
|
||||||
|
expect("🔥🔥🔥".length).toBe(6);
|
||||||
|
expect("👨👩👦".length).toBe(8);
|
||||||
|
expect("👩❤️💋👩".length).toBe(11);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("indices", () => {
|
||||||
|
expect("abc"[0]).toBe("a");
|
||||||
|
expect("abc"[1]).toBe("b");
|
||||||
|
expect("abc"[2]).toBe("c");
|
||||||
|
expect("abc"[3]).toBeUndefined();
|
||||||
|
|
||||||
|
expect("😀"[0]).toBe("\ud83d");
|
||||||
|
expect("😀"[1]).toBe("\ude00");
|
||||||
|
expect("😀"[2]).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("properties", () => {
|
||||||
|
expect(Object.getOwnPropertyNames("")).toEqual(["length"]);
|
||||||
|
expect(Object.getOwnPropertyNames("a")).toEqual(["0", "length"]);
|
||||||
|
expect(Object.getOwnPropertyNames("ab")).toEqual(["0", "1", "length"]);
|
||||||
|
expect(Object.getOwnPropertyNames("abc")).toEqual(["0", "1", "2", "length"]);
|
||||||
|
expect(Object.getOwnPropertyNames("😀")).toEqual(["0", "1", "length"]);
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue