1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 11:57:35 +00:00

LibJS: Use Optional<String> in StringPrototype

This commit is contained in:
Andreas Kling 2021-06-15 13:54:41 +02:00
parent bbf653c425
commit f20c5e1872

View file

@ -22,7 +22,7 @@
namespace JS { namespace JS {
static String ak_string_from(VM& vm, GlobalObject& global_object) static Optional<String> ak_string_from(VM& vm, GlobalObject& global_object)
{ {
auto this_value = require_object_coercible(global_object, vm.this_value(global_object)); auto this_value = require_object_coercible(global_object, vm.this_value(global_object));
if (vm.exception()) if (vm.exception())
@ -115,7 +115,7 @@ static Value this_string_value(GlobalObject& global_object, Value value)
JS_DEFINE_NATIVE_FUNCTION(StringPrototype::char_at) JS_DEFINE_NATIVE_FUNCTION(StringPrototype::char_at)
{ {
auto string = ak_string_from(vm, global_object); auto string = ak_string_from(vm, global_object);
if (string.is_null()) if (!string.has_value())
return {}; return {};
i32 index = 0; i32 index = 0;
if (vm.argument_count()) { if (vm.argument_count()) {
@ -123,17 +123,17 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::char_at)
if (vm.exception()) if (vm.exception())
return {}; return {};
} }
if (index < 0 || index >= static_cast<i32>(string.length())) if (index < 0 || index >= static_cast<i32>(string->length()))
return js_string(vm, String::empty()); return js_string(vm, String::empty());
// FIXME: This should return a character corresponding to the i'th UTF-16 code point. // FIXME: This should return a character corresponding to the i'th UTF-16 code point.
return js_string(vm, string.substring(index, 1)); return js_string(vm, string->substring(index, 1));
} }
// 22.1.3.2 String.prototype.charCodeAt ( pos ), https://tc39.es/ecma262/#sec-string.prototype.charcodeat // 22.1.3.2 String.prototype.charCodeAt ( pos ), https://tc39.es/ecma262/#sec-string.prototype.charcodeat
JS_DEFINE_NATIVE_FUNCTION(StringPrototype::char_code_at) JS_DEFINE_NATIVE_FUNCTION(StringPrototype::char_code_at)
{ {
auto string = ak_string_from(vm, global_object); auto string = ak_string_from(vm, global_object);
if (string.is_null()) if (!string.has_value())
return {}; return {};
i32 index = 0; i32 index = 0;
if (vm.argument_count()) { if (vm.argument_count()) {
@ -141,17 +141,17 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::char_code_at)
if (vm.exception()) if (vm.exception())
return {}; return {};
} }
if (index < 0 || index >= static_cast<i32>(string.length())) if (index < 0 || index >= static_cast<i32>(string->length()))
return js_nan(); return js_nan();
// FIXME: This should return the i'th UTF-16 code point. // FIXME: This should return the i'th UTF-16 code point.
return Value((i32)string[index]); return Value((i32)(*string)[index]);
} }
// 22.1.3.16 String.prototype.repeat ( count ), https://tc39.es/ecma262/#sec-string.prototype.repeat // 22.1.3.16 String.prototype.repeat ( count ), https://tc39.es/ecma262/#sec-string.prototype.repeat
JS_DEFINE_NATIVE_FUNCTION(StringPrototype::repeat) JS_DEFINE_NATIVE_FUNCTION(StringPrototype::repeat)
{ {
auto string = ak_string_from(vm, global_object); auto string = ak_string_from(vm, global_object);
if (string.is_null()) if (!string.has_value())
return {}; return {};
if (!vm.argument_count()) if (!vm.argument_count())
return js_string(vm, String::empty()); return js_string(vm, String::empty());
@ -168,7 +168,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::repeat)
} }
StringBuilder builder; StringBuilder builder;
for (size_t i = 0; i < count; ++i) for (size_t i = 0; i < count; ++i)
builder.append(string); builder.append(*string);
return js_string(vm, builder.to_string()); return js_string(vm, builder.to_string());
} }
@ -176,7 +176,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::repeat)
JS_DEFINE_NATIVE_FUNCTION(StringPrototype::starts_with) JS_DEFINE_NATIVE_FUNCTION(StringPrototype::starts_with)
{ {
auto string = ak_string_from(vm, global_object); auto string = ak_string_from(vm, global_object);
if (string.is_null()) if (!string.has_value())
return {}; return {};
auto search_string_value = vm.argument(0); auto search_string_value = vm.argument(0);
@ -193,7 +193,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::starts_with)
if (vm.exception()) if (vm.exception())
return {}; return {};
auto string_length = string.length(); auto string_length = string->length();
auto search_string_length = search_string.length(); auto search_string_length = search_string.length();
size_t start = 0; size_t start = 0;
if (!vm.argument(1).is_undefined()) { if (!vm.argument(1).is_undefined()) {
@ -206,14 +206,14 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::starts_with)
return Value(false); return Value(false);
if (search_string_length == 0) if (search_string_length == 0)
return Value(true); return Value(true);
return Value(string.substring(start, search_string_length) == search_string); return Value(string->substring(start, search_string_length) == search_string);
} }
// 22.1.3.6 String.prototype.endsWith ( searchString [ , endPosition ] ), https://tc39.es/ecma262/#sec-string.prototype.endswith // 22.1.3.6 String.prototype.endsWith ( searchString [ , endPosition ] ), https://tc39.es/ecma262/#sec-string.prototype.endswith
JS_DEFINE_NATIVE_FUNCTION(StringPrototype::ends_with) JS_DEFINE_NATIVE_FUNCTION(StringPrototype::ends_with)
{ {
auto string = ak_string_from(vm, global_object); auto string = ak_string_from(vm, global_object);
if (string.is_null()) if (!string.has_value())
return {}; return {};
auto search_string_value = vm.argument(0); auto search_string_value = vm.argument(0);
@ -230,7 +230,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::ends_with)
if (vm.exception()) if (vm.exception())
return {}; return {};
auto string_length = string.length(); auto string_length = string->length();
auto search_string_length = search_string.length(); auto search_string_length = search_string.length();
size_t pos = string_length; size_t pos = string_length;
@ -249,37 +249,37 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::ends_with)
return Value(false); return Value(false);
auto start = pos - search_string_length; auto start = pos - search_string_length;
return Value(string.substring(start, search_string_length) == search_string); return Value(string->substring(start, search_string_length) == search_string);
} }
// 22.1.3.8 String.prototype.indexOf ( searchString [ , position ] ), https://tc39.es/ecma262/#sec-string.prototype.indexof // 22.1.3.8 String.prototype.indexOf ( searchString [ , position ] ), https://tc39.es/ecma262/#sec-string.prototype.indexof
JS_DEFINE_NATIVE_FUNCTION(StringPrototype::index_of) JS_DEFINE_NATIVE_FUNCTION(StringPrototype::index_of)
{ {
auto string = ak_string_from(vm, global_object); auto string = ak_string_from(vm, global_object);
if (string.is_null()) if (!string.has_value())
return {}; return {};
auto needle = vm.argument(0).to_string(global_object); auto needle = vm.argument(0).to_string(global_object);
if (vm.exception()) if (vm.exception())
return {}; return {};
return Value((i32)string.find(needle).value_or(-1)); return Value((i32)string->find(needle).value_or(-1));
} }
// 22.1.3.26 String.prototype.toLowerCase ( ), https://tc39.es/ecma262/#sec-string.prototype.tolowercase // 22.1.3.26 String.prototype.toLowerCase ( ), https://tc39.es/ecma262/#sec-string.prototype.tolowercase
JS_DEFINE_NATIVE_FUNCTION(StringPrototype::to_lowercase) JS_DEFINE_NATIVE_FUNCTION(StringPrototype::to_lowercase)
{ {
auto string = ak_string_from(vm, global_object); auto string = ak_string_from(vm, global_object);
if (string.is_null()) if (!string.has_value())
return {}; return {};
return js_string(vm, string.to_lowercase()); return js_string(vm, string->to_lowercase());
} }
// 22.1.3.28 String.prototype.toUpperCase ( ), https://tc39.es/ecma262/#sec-string.prototype.touppercase // 22.1.3.28 String.prototype.toUpperCase ( ), https://tc39.es/ecma262/#sec-string.prototype.touppercase
JS_DEFINE_NATIVE_FUNCTION(StringPrototype::to_uppercase) JS_DEFINE_NATIVE_FUNCTION(StringPrototype::to_uppercase)
{ {
auto string = ak_string_from(vm, global_object); auto string = ak_string_from(vm, global_object);
if (string.is_null()) if (!string.has_value())
return {}; return {};
return js_string(vm, string.to_uppercase()); return js_string(vm, string->to_uppercase());
} }
// 22.1.3.27 String.prototype.toString ( ), https://tc39.es/ecma262/#sec-string.prototype.tostring // 22.1.3.27 String.prototype.toString ( ), https://tc39.es/ecma262/#sec-string.prototype.tostring
@ -335,55 +335,55 @@ static Value pad_string(GlobalObject& global_object, const String& string, PadPl
JS_DEFINE_NATIVE_FUNCTION(StringPrototype::pad_start) JS_DEFINE_NATIVE_FUNCTION(StringPrototype::pad_start)
{ {
auto string = ak_string_from(vm, global_object); auto string = ak_string_from(vm, global_object);
if (string.is_null()) if (!string.has_value())
return {}; return {};
return pad_string(global_object, string, PadPlacement::Start); return pad_string(global_object, *string, PadPlacement::Start);
} }
// 22.1.3.14 String.prototype.padEnd ( maxLength [ , fillString ] ), https://tc39.es/ecma262/#sec-string.prototype.padend // 22.1.3.14 String.prototype.padEnd ( maxLength [ , fillString ] ), https://tc39.es/ecma262/#sec-string.prototype.padend
JS_DEFINE_NATIVE_FUNCTION(StringPrototype::pad_end) JS_DEFINE_NATIVE_FUNCTION(StringPrototype::pad_end)
{ {
auto string = ak_string_from(vm, global_object); auto string = ak_string_from(vm, global_object);
if (string.is_null()) if (!string.has_value())
return {}; return {};
return pad_string(global_object, string, PadPlacement::End); return pad_string(global_object, *string, PadPlacement::End);
} }
// 22.1.3.29 String.prototype.trim ( ), https://tc39.es/ecma262/#sec-string.prototype.trim // 22.1.3.29 String.prototype.trim ( ), https://tc39.es/ecma262/#sec-string.prototype.trim
JS_DEFINE_NATIVE_FUNCTION(StringPrototype::trim) JS_DEFINE_NATIVE_FUNCTION(StringPrototype::trim)
{ {
auto string = ak_string_from(vm, global_object); auto string = ak_string_from(vm, global_object);
if (string.is_null()) if (!string.has_value())
return {}; return {};
return js_string(vm, string.trim_whitespace(TrimMode::Both)); return js_string(vm, string->trim_whitespace(TrimMode::Both));
} }
// 22.1.3.31 String.prototype.trimStart ( ), https://tc39.es/ecma262/#sec-string.prototype.trimstart // 22.1.3.31 String.prototype.trimStart ( ), https://tc39.es/ecma262/#sec-string.prototype.trimstart
JS_DEFINE_NATIVE_FUNCTION(StringPrototype::trim_start) JS_DEFINE_NATIVE_FUNCTION(StringPrototype::trim_start)
{ {
auto string = ak_string_from(vm, global_object); auto string = ak_string_from(vm, global_object);
if (string.is_null()) if (!string.has_value())
return {}; return {};
return js_string(vm, string.trim_whitespace(TrimMode::Left)); return js_string(vm, string->trim_whitespace(TrimMode::Left));
} }
// 22.1.3.30 String.prototype.trimEnd ( ), https://tc39.es/ecma262/#sec-string.prototype.trimend // 22.1.3.30 String.prototype.trimEnd ( ), https://tc39.es/ecma262/#sec-string.prototype.trimend
JS_DEFINE_NATIVE_FUNCTION(StringPrototype::trim_end) JS_DEFINE_NATIVE_FUNCTION(StringPrototype::trim_end)
{ {
auto string = ak_string_from(vm, global_object); auto string = ak_string_from(vm, global_object);
if (string.is_null()) if (!string.has_value())
return {}; return {};
return js_string(vm, string.trim_whitespace(TrimMode::Right)); return js_string(vm, string->trim_whitespace(TrimMode::Right));
} }
// 22.1.3.23 String.prototype.substring ( start, end ), https://tc39.es/ecma262/#sec-string.prototype.substring // 22.1.3.23 String.prototype.substring ( start, end ), https://tc39.es/ecma262/#sec-string.prototype.substring
JS_DEFINE_NATIVE_FUNCTION(StringPrototype::concat) JS_DEFINE_NATIVE_FUNCTION(StringPrototype::concat)
{ {
auto string = ak_string_from(vm, global_object); auto string = ak_string_from(vm, global_object);
if (string.is_null()) if (!string.has_value())
return {}; return {};
StringBuilder builder; StringBuilder builder;
builder.append(string); builder.append(*string);
for (size_t i = 0; i < vm.argument_count(); ++i) { for (size_t i = 0; i < vm.argument_count(); ++i) {
auto string_argument = vm.argument(i).to_string(global_object); auto string_argument = vm.argument(i).to_string(global_object);
if (vm.exception()) if (vm.exception())
@ -397,13 +397,13 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::concat)
JS_DEFINE_NATIVE_FUNCTION(StringPrototype::substring) JS_DEFINE_NATIVE_FUNCTION(StringPrototype::substring)
{ {
auto string = ak_string_from(vm, global_object); auto string = ak_string_from(vm, global_object);
if (string.is_null()) if (!string.has_value())
return {}; return {};
if (vm.argument_count() == 0) if (vm.argument_count() == 0)
return js_string(vm, string); return js_string(vm, *string);
// FIXME: index_start and index_end should index a UTF-16 code_point view of the string. // FIXME: index_start and index_end should index a UTF-16 code_point view of the string.
auto string_length = string.length(); auto string_length = string->length();
auto start = vm.argument(0).to_integer_or_infinity(global_object); auto start = vm.argument(0).to_integer_or_infinity(global_object);
if (vm.exception()) if (vm.exception())
return {}; return {};
@ -428,7 +428,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::substring)
} }
auto part_length = index_end - index_start; auto part_length = index_end - index_start;
auto string_part = string.substring(index_start, part_length); auto string_part = string->substring(index_start, part_length);
return js_string(vm, string_part); return js_string(vm, string_part);
} }
@ -436,13 +436,13 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::substring)
JS_DEFINE_NATIVE_FUNCTION(StringPrototype::substr) JS_DEFINE_NATIVE_FUNCTION(StringPrototype::substr)
{ {
auto string = ak_string_from(vm, global_object); auto string = ak_string_from(vm, global_object);
if (string.is_null()) if (!string.has_value())
return {}; return {};
if (vm.argument_count() == 0) if (vm.argument_count() == 0)
return js_string(vm, string); return js_string(vm, *string);
// FIXME: this should index a UTF-16 code_point view of the string. // FIXME: this should index a UTF-16 code_point view of the string.
auto size = (i32)string.length(); auto size = (i32)string->length();
auto int_start = vm.argument(0).to_integer_or_infinity(global_object); auto int_start = vm.argument(0).to_integer_or_infinity(global_object);
if (vm.exception()) if (vm.exception())
@ -466,7 +466,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::substr)
if (int_start >= int_end) if (int_start >= int_end)
return js_string(vm, String("")); return js_string(vm, String(""));
auto string_part = string.substring(int_start, int_end - int_start); auto string_part = string->substring(int_start, int_end - int_start);
return js_string(vm, string_part); return js_string(vm, string_part);
} }
@ -474,12 +474,12 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::substr)
JS_DEFINE_NATIVE_FUNCTION(StringPrototype::includes) JS_DEFINE_NATIVE_FUNCTION(StringPrototype::includes)
{ {
auto string = ak_string_from(vm, global_object); auto string = ak_string_from(vm, global_object);
if (string.is_null()) if (!string.has_value())
return {}; return {};
auto search_string = vm.argument(0).to_string(global_object); auto search_string = vm.argument(0).to_string(global_object);
if (vm.exception()) if (vm.exception())
return {}; return {};
auto string_length = string.length(); auto string_length = string->length();
// FIXME: start should index a UTF-16 code_point view of the string. // FIXME: start should index a UTF-16 code_point view of the string.
size_t start = 0; size_t start = 0;
if (!vm.argument(1).is_undefined()) { if (!vm.argument(1).is_undefined()) {
@ -489,9 +489,9 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::includes)
start = clamp(position, static_cast<double>(0), static_cast<double>(string_length)); start = clamp(position, static_cast<double>(0), static_cast<double>(string_length));
} }
if (start == 0) if (start == 0)
return Value(string.contains(search_string)); return Value(string->contains(search_string));
auto substring_length = string_length - start; auto substring_length = string_length - start;
auto substring_search = string.substring(start, substring_length); auto substring_search = string->substring(start, substring_length);
return Value(substring_search.contains(search_string)); return Value(substring_search.contains(search_string));
} }
@ -499,14 +499,14 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::includes)
JS_DEFINE_NATIVE_FUNCTION(StringPrototype::slice) JS_DEFINE_NATIVE_FUNCTION(StringPrototype::slice)
{ {
auto string = ak_string_from(vm, global_object); auto string = ak_string_from(vm, global_object);
if (string.is_null()) if (!string.has_value())
return {}; return {};
if (vm.argument_count() == 0) if (vm.argument_count() == 0)
return js_string(vm, string); return js_string(vm, *string);
// FIXME: index_start and index_end should index a UTF-16 code_point view of the string. // 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 string_length = static_cast<i32>(string->length());
auto index_start = vm.argument(0).to_i32(global_object); auto index_start = vm.argument(0).to_i32(global_object);
if (vm.exception()) if (vm.exception())
return {}; return {};
@ -536,7 +536,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::slice)
return js_string(vm, String::empty()); return js_string(vm, String::empty());
auto part_length = index_end - index_start; auto part_length = index_end - index_start;
auto string_part = string.substring(index_start, part_length); auto string_part = string->substring(index_start, part_length);
return js_string(vm, string_part); return js_string(vm, string_part);
} }
@ -546,7 +546,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::split)
// FIXME Implement the @@split part // FIXME Implement the @@split part
auto string = ak_string_from(vm, global_object); auto string = ak_string_from(vm, global_object);
if (string.is_null()) if (!string.has_value())
return {}; return {};
auto* result = Array::create(global_object); auto* result = Array::create(global_object);
@ -567,15 +567,15 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::split)
return result; return result;
if (vm.argument(0).is_undefined()) { if (vm.argument(0).is_undefined()) {
result->define_property(0, js_string(vm, string)); result->define_property(0, js_string(vm, *string));
return result; return result;
} }
auto len = string.length(); auto len = string->length();
auto separator_len = separator.length(); auto separator_len = separator.length();
if (len == 0) { if (len == 0) {
if (separator_len > 0) if (separator_len > 0)
result->define_property(0, js_string(vm, string)); result->define_property(0, js_string(vm, *string));
return result; return result;
} }
@ -583,18 +583,18 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::split)
auto pos = start; auto pos = start;
if (separator_len == 0) { if (separator_len == 0) {
for (pos = 0; pos < len; pos++) for (pos = 0; pos < len; pos++)
result->define_property(pos, js_string(vm, string.substring(pos, 1))); result->define_property(pos, js_string(vm, string->substring(pos, 1)));
return result; return result;
} }
while (pos != len) { while (pos != len) {
auto e = split_match(string, pos, separator); auto e = split_match(*string, pos, separator);
if (!e.has_value()) { if (!e.has_value()) {
pos += 1; pos += 1;
continue; continue;
} }
auto segment = string.substring_view(start, pos - start); auto segment = string->substring_view(start, pos - start);
result->define_property(result_len, js_string(vm, segment)); result->define_property(result_len, js_string(vm, segment));
result_len++; result_len++;
if (result_len == limit) if (result_len == limit)
@ -603,7 +603,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::split)
pos = start; pos = start;
} }
auto rest = string.substring(start, len - start); auto rest = string->substring(start, len - start);
result->define_property(result_len, js_string(vm, rest)); result->define_property(result_len, js_string(vm, rest));
return result; return result;
@ -613,7 +613,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::split)
JS_DEFINE_NATIVE_FUNCTION(StringPrototype::last_index_of) JS_DEFINE_NATIVE_FUNCTION(StringPrototype::last_index_of)
{ {
auto string = ak_string_from(vm, global_object); auto string = ak_string_from(vm, global_object);
if (string.is_null()) if (!string.has_value())
return {}; return {};
auto search_string = vm.argument(0).to_string(global_object); auto search_string = vm.argument(0).to_string(global_object);
if (vm.exception()) if (vm.exception())
@ -621,9 +621,9 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::last_index_of)
auto position = vm.argument(1).to_number(global_object); auto position = vm.argument(1).to_number(global_object);
if (vm.exception()) if (vm.exception())
return {}; return {};
if (search_string.length() > string.length()) if (search_string.length() > string->length())
return Value(-1); return Value(-1);
auto max_index = string.length() - search_string.length(); auto max_index = string->length() - search_string.length();
auto from_index = max_index; auto from_index = max_index;
if (!position.is_nan()) { if (!position.is_nan()) {
// FIXME: from_index should index a UTF-16 code_point view of the string. // FIXME: from_index should index a UTF-16 code_point view of the string.
@ -634,7 +634,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::last_index_of)
} }
for (i32 i = from_index; i >= 0; --i) { for (i32 i = from_index; i >= 0; --i) {
auto part_view = string.substring_view(i, search_string.length()); auto part_view = string->substring_view(i, search_string.length());
if (part_view == search_string) if (part_view == search_string)
return Value(i); return Value(i);
} }
@ -646,9 +646,9 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::last_index_of)
JS_DEFINE_NATIVE_FUNCTION(StringPrototype::at) JS_DEFINE_NATIVE_FUNCTION(StringPrototype::at)
{ {
auto string = ak_string_from(vm, global_object); auto string = ak_string_from(vm, global_object);
if (string.is_null()) if (!string.has_value())
return {}; return {};
auto length = string.length(); auto length = string->length();
auto relative_index = vm.argument(0).to_integer_or_infinity(global_object); auto relative_index = vm.argument(0).to_integer_or_infinity(global_object);
if (vm.exception()) if (vm.exception())
return {}; return {};
@ -663,7 +663,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::at)
} }
if (index.has_overflow() || index.value() >= length) if (index.has_overflow() || index.value() >= length)
return js_undefined(); return js_undefined();
return js_string(vm, String::formatted("{}", string[index.value()])); return js_string(vm, String::formatted("{}", (*string)[index.value()]));
} }
// 22.1.3.33 String.prototype [ @@iterator ] ( ), https://tc39.es/ecma262/#sec-string.prototype-@@iterator // 22.1.3.33 String.prototype [ @@iterator ] ( ), https://tc39.es/ecma262/#sec-string.prototype-@@iterator