summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimothy Flynn <trflynn89@pm.me>2021-07-19 14:57:07 -0400
committerAndreas Kling <kling@serenityos.org>2021-07-22 09:10:44 +0200
commit5ac964d84115b5b844f4dc72b88a4b1f22b941a1 (patch)
tree1c5c8fa7a895128b6c21b54ecd20f1f0a4643704
parenteaa1360eee1c9276310074f1087fbb5ac733b55c (diff)
downloadserenity-5ac964d84115b5b844f4dc72b88a4b1f22b941a1.zip
LibJS: Implement String.prototype.slice with UTF-16 code units
This also implements String.prototype.slice more closely to the spec (such as handling indices equivalent to Infinity).
-rw-r--r--Userland/Libraries/LibJS/Runtime/StringPrototype.cpp50
-rw-r--r--Userland/Libraries/LibJS/Tests/builtins/String/String.prototype.slice.js10
2 files changed, 32 insertions, 28 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/StringPrototype.cpp b/Userland/Libraries/LibJS/Runtime/StringPrototype.cpp
index 12daf89f10..9bbadd5077 100644
--- a/Userland/Libraries/LibJS/Runtime/StringPrototype.cpp
+++ b/Userland/Libraries/LibJS/Runtime/StringPrototype.cpp
@@ -610,46 +610,40 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::includes)
// 22.1.3.20 String.prototype.slice ( start, end ), https://tc39.es/ecma262/#sec-string.prototype.slice
JS_DEFINE_NATIVE_FUNCTION(StringPrototype::slice)
{
- auto string = ak_string_from(vm, global_object);
- if (!string.has_value())
+ auto string = utf16_string_from(vm, global_object);
+ if (vm.exception())
return {};
- if (vm.argument_count() == 0)
- return js_string(vm, *string);
+ Utf16View utf16_string_view { string };
+ auto string_length = static_cast<double>(utf16_string_view.length_in_code_units());
- // FIXME: index_start and index_end should index a UTF-16 code_point view of the string.
- auto string_length = static_cast<i32>(string->length());
- auto index_start = vm.argument(0).to_i32(global_object);
+ auto int_start = vm.argument(0).to_integer_or_infinity(global_object);
if (vm.exception())
return {};
- auto index_end = string_length;
-
- auto negative_min_index = -(string_length - 1);
- if (index_start < negative_min_index)
- index_start = 0;
- else if (index_start < 0)
- index_start = string_length + index_start;
+ if (Value(int_start).is_negative_infinity())
+ int_start = 0;
+ else if (int_start < 0)
+ int_start = max(string_length + int_start, 0);
+ else
+ int_start = min(int_start, string_length);
- if (vm.argument_count() >= 2) {
- index_end = vm.argument(1).to_i32(global_object);
+ auto int_end = string_length;
+ if (!vm.argument(1).is_undefined()) {
+ int_end = vm.argument(1).to_integer_or_infinity(global_object);
if (vm.exception())
return {};
-
- if (index_end < negative_min_index)
- return js_string(vm, String::empty());
-
- if (index_end > string_length)
- index_end = string_length;
- else if (index_end < 0)
- index_end = string_length + index_end;
+ if (Value(int_end).is_negative_infinity())
+ int_end = 0;
+ else if (int_end < 0)
+ int_end = max(string_length + int_end, 0);
+ else
+ int_end = min(int_end, string_length);
}
- if (index_start >= index_end)
+ if (int_start >= int_end)
return js_string(vm, String::empty());
- auto part_length = index_end - index_start;
- auto string_part = string->substring(index_start, part_length);
- return js_string(vm, string_part);
+ return js_string(vm, utf16_string_view.substring_view(int_start, int_end - int_start));
}
// 22.1.3.21 String.prototype.split ( separator, limit ), https://tc39.es/ecma262/#sec-string.prototype.split
diff --git a/Userland/Libraries/LibJS/Tests/builtins/String/String.prototype.slice.js b/Userland/Libraries/LibJS/Tests/builtins/String/String.prototype.slice.js
index 2141e0f6f3..58ffe4649a 100644
--- a/Userland/Libraries/LibJS/Tests/builtins/String/String.prototype.slice.js
+++ b/Userland/Libraries/LibJS/Tests/builtins/String/String.prototype.slice.js
@@ -15,3 +15,13 @@ test("basic functionality", () => {
expect("hello friends".slice(1000)).toBe("");
expect("hello friends".slice(-1000)).toBe("hello friends");
});
+
+test("UTF-16", () => {
+ var s = "😀";
+ expect(s).toHaveLength(2);
+ expect(s.slice()).toBe("😀");
+ expect(s.slice(0)).toBe("😀");
+ expect(s.slice(1)).toBe("\ude00");
+ expect(s.slice(0, 1)).toBe("\ud83d");
+ expect(s.slice(0, 2)).toBe("😀");
+});