Libraries: Use UTF-16 for JS-visible runtime strings
Produce JS-visible string results as UTF-16 at their source, including numeric formatting, BigInt and BigFraction formatting, URI encoding, console formatting, parser errors, regular expression errors, Intl and Temporal records, LibUnicode locale boundaries, and LibWeb bindings. Handle fractional radix formatting through the UTF-16 builder view.
This commit is contained in:
parent
7025dd1fa7
commit
b6bef6b688
286 changed files with 3042 additions and 2631 deletions
|
|
@ -138,6 +138,22 @@ static ErrorOr<String> encode_base64_impl(ReadonlyBytes input, simdutf::base64_o
|
|||
return String { move(output) };
|
||||
}
|
||||
|
||||
static Utf16String encode_base64_to_utf16_impl(ReadonlyBytes input, simdutf::base64_options options)
|
||||
{
|
||||
if (input.is_empty())
|
||||
return {};
|
||||
|
||||
return Utf16String::create_uninitialized_ascii(
|
||||
simdutf::base64_length_from_binary(input.size(), options),
|
||||
[&](Bytes buffer) {
|
||||
simdutf::binary_to_base64(
|
||||
reinterpret_cast<char const*>(input.data()),
|
||||
input.size(),
|
||||
reinterpret_cast<char*>(buffer.data()),
|
||||
options);
|
||||
});
|
||||
}
|
||||
|
||||
ErrorOr<ByteBuffer> decode_base64(StringView input, LastChunkHandling last_chunk_handling)
|
||||
{
|
||||
return decode_base64_impl(input, last_chunk_handling, simdutf::base64_default);
|
||||
|
|
@ -186,4 +202,22 @@ ErrorOr<String> encode_base64url(ReadonlyBytes input, OmitPadding omit_padding)
|
|||
return encode_base64_impl(input, options);
|
||||
}
|
||||
|
||||
ErrorOr<Utf16String> encode_base64_to_utf16(ReadonlyBytes input, OmitPadding omit_padding)
|
||||
{
|
||||
auto options = omit_padding == OmitPadding::Yes
|
||||
? simdutf::base64_default_no_padding
|
||||
: simdutf::base64_default;
|
||||
|
||||
return encode_base64_to_utf16_impl(input, options);
|
||||
}
|
||||
|
||||
ErrorOr<Utf16String> encode_base64url_to_utf16(ReadonlyBytes input, OmitPadding omit_padding)
|
||||
{
|
||||
auto options = omit_padding == OmitPadding::Yes
|
||||
? simdutf::base64_url
|
||||
: simdutf::base64_url_with_padding;
|
||||
|
||||
return encode_base64_to_utf16_impl(input, options);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <AK/Error.h>
|
||||
#include <AK/String.h>
|
||||
#include <AK/StringView.h>
|
||||
#include <AK/Utf16String.h>
|
||||
#include <AK/Utf16View.h>
|
||||
|
||||
namespace AK {
|
||||
|
|
@ -45,6 +46,8 @@ enum class OmitPadding {
|
|||
|
||||
ErrorOr<String> encode_base64(ReadonlyBytes, OmitPadding = OmitPadding::No);
|
||||
ErrorOr<String> encode_base64url(ReadonlyBytes, OmitPadding = OmitPadding::No);
|
||||
ErrorOr<Utf16String> encode_base64_to_utf16(ReadonlyBytes, OmitPadding = OmitPadding::No);
|
||||
ErrorOr<Utf16String> encode_base64url_to_utf16(ReadonlyBytes, OmitPadding = OmitPadding::No);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -52,5 +55,7 @@ ErrorOr<String> encode_base64url(ReadonlyBytes, OmitPadding = OmitPadding::No);
|
|||
using AK::decode_base64;
|
||||
using AK::decode_base64url;
|
||||
using AK::encode_base64;
|
||||
using AK::encode_base64_to_utf16;
|
||||
using AK::encode_base64url;
|
||||
using AK::encode_base64url_to_utf16;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -239,6 +239,23 @@ public:
|
|||
static Utf16String from_string_builder(Badge<Utf16StringBuilder>, Utf16StringBuilder& builder);
|
||||
static ErrorOr<Utf16String> from_ipc_stream(Stream&, size_t length_in_code_units, bool is_ascii);
|
||||
|
||||
template<typename Callback>
|
||||
static Utf16String create_uninitialized_ascii(size_t length_in_code_units, Callback callback)
|
||||
{
|
||||
if (length_in_code_units <= Detail::MAX_SHORT_STRING_BYTE_COUNT) {
|
||||
Utf16String string;
|
||||
string.m_value.short_ascii_string = Detail::ShortString::create_with_byte_count(length_in_code_units);
|
||||
|
||||
callback({ string.m_value.short_ascii_string.storage, length_in_code_units });
|
||||
return string;
|
||||
}
|
||||
|
||||
Bytes buffer;
|
||||
Utf16String string { Detail::Utf16StringData::create_uninitialized_ascii(length_in_code_units, buffer) };
|
||||
callback(buffer);
|
||||
return string;
|
||||
}
|
||||
|
||||
constexpr Utf16String(Badge<Optional<Utf16String>>, nullptr_t)
|
||||
: Detail::Utf16StringBase(Badge<Utf16String> {}, nullptr)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -63,6 +63,15 @@ NonnullRefPtr<Utf16StringData> Utf16StringData::from_ascii(ReadonlyBytes ascii_s
|
|||
return string;
|
||||
}
|
||||
|
||||
NonnullRefPtr<Utf16StringData> Utf16StringData::create_uninitialized_ascii(size_t length_in_code_units, Bytes& buffer)
|
||||
{
|
||||
VERIFY_UTF16_LENGTH(length_in_code_units);
|
||||
|
||||
auto string = create_uninitialized(StorageType::ASCII, length_in_code_units);
|
||||
buffer = { string->m_ascii_data, length_in_code_units };
|
||||
return string;
|
||||
}
|
||||
|
||||
NonnullRefPtr<Utf16StringData> Utf16StringData::from_utf8(StringView utf8_string, AllowASCIIStorage allow_ascii_storage)
|
||||
{
|
||||
RefPtr<Utf16StringData> string;
|
||||
|
|
|
|||
|
|
@ -15,6 +15,12 @@
|
|||
#include <AK/Utf16View.h>
|
||||
#include <AK/kmalloc.h>
|
||||
|
||||
namespace AK {
|
||||
|
||||
class Utf16String;
|
||||
|
||||
}
|
||||
|
||||
namespace AK::Detail {
|
||||
|
||||
void did_destroy_utf16_fly_string_data(Badge<Detail::Utf16StringData>, Detail::Utf16StringData const&);
|
||||
|
|
@ -118,6 +124,8 @@ public:
|
|||
[[nodiscard]] ALWAYS_INLINE bool is_fly_string() const { return m_is_fly_string; }
|
||||
|
||||
private:
|
||||
friend class AK::Utf16String;
|
||||
|
||||
ALWAYS_INLINE Utf16StringData(StorageType storage_type, size_t code_unit_length)
|
||||
: m_length_in_code_units(code_unit_length)
|
||||
{
|
||||
|
|
@ -126,6 +134,7 @@ private:
|
|||
}
|
||||
|
||||
static NonnullRefPtr<Utf16StringData> create_uninitialized(StorageType storage_type, size_t code_unit_length);
|
||||
static NonnullRefPtr<Utf16StringData> create_uninitialized_ascii(size_t length_in_code_units, Bytes& buffer);
|
||||
|
||||
template<typename ViewType>
|
||||
static NonnullRefPtr<Utf16StringData> create_from_code_point_iterable(ViewType const&);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@ namespace Core::TimeZone {
|
|||
|
||||
ErrorOr<void> set_current_time_zone(StringView time_zone)
|
||||
{
|
||||
TRY(Unicode::set_current_time_zone(time_zone));
|
||||
auto time_zone_utf16 = Utf16String::from_utf8(time_zone);
|
||||
TRY(Unicode::set_current_time_zone(time_zone_utf16));
|
||||
TRY(Core::Environment::set("TZ"sv, time_zone, Core::Environment::Overwrite::Yes));
|
||||
tzset();
|
||||
return {};
|
||||
|
|
@ -21,7 +22,8 @@ ErrorOr<void> set_current_time_zone(StringView time_zone)
|
|||
|
||||
String current_time_zone()
|
||||
{
|
||||
return Unicode::current_time_zone();
|
||||
auto time_zone = Unicode::current_time_zone();
|
||||
return time_zone.utf16_view().to_utf8_but_should_be_ported_to_utf16();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/ByteString.h>
|
||||
#include <AK/Math.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <AK/Utf16StringBuilder.h>
|
||||
#include <LibCrypto/BigFraction/BigFraction.h>
|
||||
#include <LibCrypto/BigInt/UnsignedBigInteger.h>
|
||||
|
||||
|
|
@ -233,11 +233,11 @@ void BigFraction::reduce()
|
|||
m_denominator = denominator_divide.quotient;
|
||||
}
|
||||
|
||||
String BigFraction::to_string(unsigned rounding_threshold) const
|
||||
Utf16String BigFraction::to_utf16_string(unsigned rounding_threshold) const
|
||||
{
|
||||
StringBuilder builder;
|
||||
Utf16StringBuilder builder;
|
||||
if (m_numerator.is_negative() && m_numerator != "0"_bigint)
|
||||
builder.append('-');
|
||||
builder.append_ascii('-');
|
||||
|
||||
auto const number_of_digits = [](auto integer) {
|
||||
unsigned size = 1;
|
||||
|
|
@ -256,43 +256,48 @@ String BigFraction::to_string(unsigned rounding_threshold) const
|
|||
auto const rounded_fraction = rounded(rounding_threshold);
|
||||
|
||||
// We take the unsigned value as we already manage the '-'
|
||||
auto const full_value = MUST(rounded_fraction.m_numerator.unsigned_value().to_base(10)).to_byte_string();
|
||||
int split = full_value.length() - (number_of_digits(rounded_fraction.m_denominator) - 1);
|
||||
auto const full_value = MUST(rounded_fraction.m_numerator.unsigned_value().to_base_utf16(10));
|
||||
int split = full_value.length_in_code_units() - (number_of_digits(rounded_fraction.m_denominator) - 1);
|
||||
|
||||
if (split < 0)
|
||||
split = 0;
|
||||
|
||||
auto const remove_trailing_zeros = [](StringView value) -> StringView {
|
||||
auto n = value.length();
|
||||
auto const remove_trailing_zeros = [](Utf16View value) -> Utf16View {
|
||||
auto n = value.length_in_code_units();
|
||||
VERIFY(n > 0);
|
||||
while (n > 0 && value.characters_without_null_termination()[n - 1] == '0')
|
||||
while (n > 0 && value.code_unit_at(n - 1) == '0')
|
||||
--n;
|
||||
return { value.characters_without_null_termination(), n };
|
||||
return value.substring_view(0, n);
|
||||
};
|
||||
|
||||
auto const raw_fractional_value = full_value.substring(split, full_value.length() - split);
|
||||
auto const raw_fractional_value = full_value.substring_view(split, full_value.length_in_code_units() - split);
|
||||
|
||||
auto const integer_value = split == 0 ? "0"sv : full_value.substring_view(0, split);
|
||||
auto const fractional_value = rounding_threshold == 0 ? "0"sv : remove_trailing_zeros(raw_fractional_value);
|
||||
Utf16View integer_value = "0"sv;
|
||||
if (split != 0)
|
||||
integer_value = full_value.substring_view(0, split);
|
||||
|
||||
Utf16View fractional_value = "0"sv;
|
||||
if (rounding_threshold != 0)
|
||||
fractional_value = remove_trailing_zeros(raw_fractional_value);
|
||||
|
||||
builder.append(integer_value);
|
||||
|
||||
bool const has_decimal_part = fractional_value.length() > 0 && fractional_value != "0";
|
||||
bool const has_decimal_part = fractional_value.length_in_code_units() > 0 && fractional_value != "0"sv;
|
||||
|
||||
if (has_decimal_part) {
|
||||
builder.append('.');
|
||||
builder.append_ascii('.');
|
||||
|
||||
auto number_pre_zeros = number_of_digits(rounded_fraction.m_denominator) - full_value.length() - 1;
|
||||
if (number_pre_zeros > rounding_threshold || fractional_value == "0")
|
||||
auto number_pre_zeros = number_of_digits(rounded_fraction.m_denominator) - full_value.length_in_code_units() - 1;
|
||||
if (number_pre_zeros > rounding_threshold || fractional_value == "0"sv)
|
||||
number_pre_zeros = 0;
|
||||
|
||||
builder.append_repeated('0', number_pre_zeros);
|
||||
builder.append_repeated_ascii('0', number_pre_zeros);
|
||||
|
||||
if (fractional_value != "0")
|
||||
if (fractional_value != "0"sv)
|
||||
builder.append(fractional_value);
|
||||
}
|
||||
|
||||
return MUST(builder.to_string());
|
||||
return builder.to_string();
|
||||
}
|
||||
|
||||
BigFraction BigFraction::sqrt() const
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Utf16String.h>
|
||||
#include <LibCrypto/BigInt/SignedBigInteger.h>
|
||||
|
||||
namespace Crypto {
|
||||
|
|
@ -55,7 +56,7 @@ public:
|
|||
// - m_denominator = 10000
|
||||
BigFraction rounded(unsigned rounding_threshold) const;
|
||||
|
||||
String to_string(unsigned rounding_threshold) const;
|
||||
Utf16String to_utf16_string(unsigned rounding_threshold) const;
|
||||
double to_double() const;
|
||||
|
||||
Crypto::SignedBigInteger const& numerator() const& { return m_numerator; }
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@
|
|||
#include <math.h>
|
||||
#include <tommath.h>
|
||||
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <AK/Utf16StringBuilder.h>
|
||||
#include <LibCrypto/BigInt/SignedBigInteger.h>
|
||||
#include <LibCrypto/BigInt/Tommath.h>
|
||||
|
||||
|
|
@ -170,6 +172,28 @@ ErrorOr<String> SignedBigInteger::to_base(u16 N) const
|
|||
return StringView(buffer.bytes().slice(0, written - 1)).to_ascii_lowercase_string();
|
||||
}
|
||||
|
||||
ErrorOr<Utf16String> SignedBigInteger::to_base_utf16(u16 N) const
|
||||
{
|
||||
VERIFY(N <= 36);
|
||||
if (is_zero())
|
||||
return "0"_utf16;
|
||||
|
||||
int size = 0;
|
||||
MP_MUST(mp_radix_size(&m_mp, N, &size));
|
||||
auto buffer = TRY(ByteBuffer::create_zeroed(size));
|
||||
|
||||
size_t written = 0;
|
||||
MP_MUST(mp_to_radix(&m_mp, reinterpret_cast<char*>(buffer.data()), size, &written, N));
|
||||
|
||||
Utf16StringBuilder builder(written - 1);
|
||||
for (auto character : buffer.bytes().slice(0, written - 1)) {
|
||||
if (character >= 'A' && character <= 'Z')
|
||||
character += 'a' - 'A';
|
||||
builder.append_code_unit(character);
|
||||
}
|
||||
return builder.to_string();
|
||||
}
|
||||
|
||||
i64 SignedBigInteger::to_i64() const
|
||||
{
|
||||
return mp_get_i64(&m_mp);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Utf16String.h>
|
||||
#include <LibCrypto/BigInt/UnsignedBigInteger.h>
|
||||
|
||||
namespace Crypto {
|
||||
|
|
@ -44,6 +45,7 @@ public:
|
|||
[[nodiscard]] static ErrorOr<SignedBigInteger> from_base(u16 N, StringView str);
|
||||
[[nodiscard]] static ErrorOr<SignedBigInteger> from_base(u16 N, Utf16View str);
|
||||
[[nodiscard]] ErrorOr<String> to_base(u16 N) const;
|
||||
[[nodiscard]] ErrorOr<Utf16String> to_base_utf16(u16 N) const;
|
||||
|
||||
[[nodiscard]] i64 to_i64() const;
|
||||
[[nodiscard]] u64 to_u64() const;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
#include <AK/BuiltinWrappers.h>
|
||||
#include <AK/FloatingPoint.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <AK/Utf16StringBuilder.h>
|
||||
#include <LibCrypto/BigInt/Tommath.h>
|
||||
#include <LibCrypto/BigInt/UnsignedBigInteger.h>
|
||||
|
||||
|
|
@ -172,6 +174,28 @@ ErrorOr<String> UnsignedBigInteger::to_base(u16 N) const
|
|||
return StringView(buffer.bytes().slice(0, written - 1)).to_ascii_lowercase_string();
|
||||
}
|
||||
|
||||
ErrorOr<Utf16String> UnsignedBigInteger::to_base_utf16(u16 N) const
|
||||
{
|
||||
VERIFY(N <= 36);
|
||||
if (is_zero())
|
||||
return "0"_utf16;
|
||||
|
||||
int size = 0;
|
||||
MP_MUST(mp_radix_size(&m_mp, N, &size));
|
||||
auto buffer = TRY(ByteBuffer::create_zeroed(size));
|
||||
|
||||
size_t written = 0;
|
||||
MP_MUST(mp_to_radix(&m_mp, reinterpret_cast<char*>(buffer.data()), size, &written, N));
|
||||
|
||||
Utf16StringBuilder builder(written - 1);
|
||||
for (auto character : buffer.bytes().slice(0, written - 1)) {
|
||||
if (character >= 'A' && character <= 'Z')
|
||||
character += 'a' - 'A';
|
||||
builder.append_code_unit(character);
|
||||
}
|
||||
return builder.to_string();
|
||||
}
|
||||
|
||||
size_t UnsignedBigInteger::count_digits_in_base(u16 base) const
|
||||
{
|
||||
VERIFY(base <= 36);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/String.h>
|
||||
#include <AK/Utf16String.h>
|
||||
#include <AK/Utf16View.h>
|
||||
#include <LibCrypto/BigInt/TommathForward.h>
|
||||
|
||||
|
|
@ -47,6 +48,7 @@ public:
|
|||
[[nodiscard]] static ErrorOr<UnsignedBigInteger> from_base(u16 N, StringView str);
|
||||
[[nodiscard]] static ErrorOr<UnsignedBigInteger> from_base(u16 N, Utf16View str);
|
||||
[[nodiscard]] ErrorOr<String> to_base(u16 N) const;
|
||||
[[nodiscard]] ErrorOr<Utf16String> to_base_utf16(u16 N) const;
|
||||
|
||||
[[nodiscard]] size_t count_digits_in_base(u16 base) const;
|
||||
|
||||
|
|
|
|||
|
|
@ -245,7 +245,7 @@ static ThrowCompletionOr<void> asm_create_variable(VM& vm, Utf16FlyString const&
|
|||
// Note: This is papering over an issue where "FunctionDeclarationInstantiation" creates these bindings for us.
|
||||
// Instead of crashing in there, we'll just raise an exception here.
|
||||
if (TRY(vm.lexical_environment()->has_binding(name))) [[unlikely]]
|
||||
return vm.throw_completion<InternalError>(TRY_OR_THROW_OOM(vm, String::formatted("Lexical environment already has binding '{}'", name)));
|
||||
return vm.throw_completion<InternalError>(Utf16String::formatted("Lexical environment already has binding '{}'", name));
|
||||
|
||||
if (is_immutable)
|
||||
return vm.lexical_environment()->create_immutable_binding(vm, name, is_strict);
|
||||
|
|
@ -2344,7 +2344,7 @@ i64 asm_slow_path_dynamic_typeof_binding(VM* vm, u32 pc, Op::DynamicTypeofBindin
|
|||
|
||||
auto reference = ASM_TRY(*vm, pc, vm->resolve_binding(vm->get_identifier(instruction->identifier()), instruction->strict()));
|
||||
if (reference.is_unresolvable()) {
|
||||
vm->set(instruction->dst(), PrimitiveString::create(*vm, "undefined"_string));
|
||||
vm->set(instruction->dst(), PrimitiveString::create(*vm, "undefined"_utf16_fly_string));
|
||||
return static_cast<i64>(pc + sizeof(Op::DynamicTypeofBinding));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -409,7 +409,7 @@ static void dump_metadata(StringBuilder& output, Executable const& executable)
|
|||
else if (value.is_double())
|
||||
output.appendff("Double({})", value.as_double());
|
||||
else if (value.is_bigint())
|
||||
output.appendff("BigInt({})", MUST(value.as_bigint().to_string()));
|
||||
output.appendff("BigInt({})", value.as_bigint().to_utf16_string());
|
||||
else if (value.is_string())
|
||||
output.appendff("String(\"{}\")", value.as_string().utf16_string_view());
|
||||
else if (value.is_undefined())
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ ThrowCompletionOr<Value> Console::assert_()
|
|||
return js_undefined();
|
||||
|
||||
// 2. Let message be a string without any formatting specifiers indicating generically an assertion failure (such as "Assertion failed").
|
||||
auto message = PrimitiveString::create(vm, "Assertion failed"_string);
|
||||
auto message = PrimitiveString::create(vm, "Assertion failed"_utf16_fly_string);
|
||||
|
||||
// NOTE: Assemble `data` from the function arguments.
|
||||
GC::RootVector<Value> data;
|
||||
|
|
@ -362,7 +362,7 @@ ThrowCompletionOr<Value> Console::trace()
|
|||
Console::TraceFrame frame;
|
||||
|
||||
auto function_name = (context && context->function) ? context->function->name_for_call_stack() : ""_utf16;
|
||||
frame.function_name = function_name.is_empty() ? "<anonymous>"_string : function_name.to_utf8();
|
||||
frame.function_name = function_name.is_empty() ? "<anonymous>"_utf16 : function_name;
|
||||
|
||||
if (element.source_range.has_value()) {
|
||||
auto const& source_range = *element.source_range;
|
||||
|
|
@ -963,19 +963,17 @@ ThrowCompletionOr<GC::RootVector<Value>> ConsoleClient::formatter(GC::RootVector
|
|||
|
||||
ThrowCompletionOr<Utf16String> ConsoleClient::generically_format_values(GC::RootVector<Value> const& values)
|
||||
{
|
||||
AllocatingMemoryStream stream;
|
||||
auto& vm = m_console->realm().vm();
|
||||
PrintContext ctx { vm, stream, true };
|
||||
Utf16StringBuilder builder;
|
||||
PrintContext ctx { .vm = vm, .builder = &builder, .strip_ansi = true };
|
||||
bool first = true;
|
||||
for (auto const& value : values) {
|
||||
if (!first)
|
||||
TRY_OR_THROW_OOM(vm, stream.write_until_depleted(" "sv.bytes()));
|
||||
builder.append_ascii(' ');
|
||||
TRY_OR_THROW_OOM(vm, JS::print(value, ctx));
|
||||
first = false;
|
||||
}
|
||||
// FIXME: Is it possible we could end up serializing objects to invalid UTF-8?
|
||||
auto output = TRY_OR_THROW_OOM(vm, String::from_stream(stream, stream.used_buffer_size()));
|
||||
return Utf16String::from_utf8(output);
|
||||
return builder.to_string();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ public:
|
|||
};
|
||||
|
||||
struct TraceFrame {
|
||||
String function_name;
|
||||
Utf16String function_name;
|
||||
Optional<String> source_file;
|
||||
Optional<size_t> line;
|
||||
Optional<size_t> column;
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ JS_DEFINE_NATIVE_FUNCTION($262Object::eval_script)
|
|||
auto& error = script_or_error.error()[0];
|
||||
|
||||
// b. Return Completion { [[Type]]: throw, [[Value]]: error, [[Target]]: empty }.
|
||||
return vm.throw_completion<SyntaxError>(error.to_string());
|
||||
return vm.throw_completion<SyntaxError>(error.to_utf16_string());
|
||||
}
|
||||
|
||||
// 5. Let status be ScriptEvaluation(s).
|
||||
|
|
|
|||
|
|
@ -13,18 +13,18 @@
|
|||
|
||||
namespace JS {
|
||||
|
||||
String ParserError::to_string() const
|
||||
Utf16String ParserError::to_utf16_string() const
|
||||
{
|
||||
if (!position.has_value())
|
||||
return message;
|
||||
return MUST(String::formatted("{} (line: {}, column: {})", message, position.value().line, position.value().column));
|
||||
return Utf16String::formatted("{} (line: {}, column: {})", message, position.value().line, position.value().column);
|
||||
}
|
||||
|
||||
ByteString ParserError::to_byte_string() const
|
||||
{
|
||||
if (!position.has_value())
|
||||
return message.to_byte_string();
|
||||
return ByteString::formatted("{} (line: {}, column: {})", message, position.value().line, position.value().column);
|
||||
return Utf16String::formatted("{} (line: {}, column: {})", message, position.value().line, position.value().column).to_byte_string();
|
||||
}
|
||||
|
||||
ByteString ParserError::source_location_hint(Utf16View const& source, char spacer, char indicator) const
|
||||
|
|
|
|||
|
|
@ -10,17 +10,17 @@
|
|||
#include <AK/ByteString.h>
|
||||
#include <AK/Error.h>
|
||||
#include <AK/Optional.h>
|
||||
#include <AK/String.h>
|
||||
#include <AK/Utf16String.h>
|
||||
#include <LibJS/Export.h>
|
||||
#include <LibJS/SourceRange.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
struct JS_API ParserError {
|
||||
String message;
|
||||
Utf16String message;
|
||||
Optional<Position> position;
|
||||
|
||||
String to_string() const;
|
||||
Utf16String to_utf16_string() const;
|
||||
ByteString to_byte_string() const;
|
||||
ByteString source_location_hint(Utf16View const& source, char spacer = ' ', char indicator = '^') const;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <AK/Concepts.h>
|
||||
#include <AK/Stream.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <AK/Utf16StringBuilder.h>
|
||||
#include <LibJS/Print.h>
|
||||
#include <LibJS/Runtime/Array.h>
|
||||
|
|
@ -140,9 +141,21 @@ ErrorOr<void> js_out(JS::PrintContext& print_context, CheckedFormatString<Args..
|
|||
{
|
||||
if (print_context.strip_ansi) {
|
||||
auto format_string_without_ansi = TRY(strip_ansi(format_string.view()));
|
||||
TRY(print_context.stream.write_formatted(format_string_without_ansi, args...));
|
||||
if (print_context.builder) {
|
||||
AK::VariadicFormatParams<AK::AllowDebugOnlyFormatters::No, Args...> variadic_format_parameters { args... };
|
||||
TRY(vformat(*print_context.builder, format_string_without_ansi.bytes_as_string_view(), variadic_format_parameters));
|
||||
} else {
|
||||
TRY(print_context.stream.write_formatted(format_string.view(), args...));
|
||||
VERIFY(print_context.stream);
|
||||
TRY(print_context.stream->write_formatted(format_string_without_ansi, args...));
|
||||
}
|
||||
} else {
|
||||
if (print_context.builder) {
|
||||
AK::VariadicFormatParams<AK::AllowDebugOnlyFormatters::No, Args...> variadic_format_parameters { args... };
|
||||
TRY(vformat(*print_context.builder, format_string.view(), variadic_format_parameters));
|
||||
} else {
|
||||
VERIFY(print_context.stream);
|
||||
TRY(print_context.stream->write_formatted(format_string.view(), args...));
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
|
|
@ -684,7 +697,7 @@ ErrorOr<void> print_intl_date_time_format(JS::PrintContext& print_context, JS::I
|
|||
return JS::throw_completion(JS::js_null());
|
||||
} else {
|
||||
auto name = Unicode::calendar_pattern_style_to_string(*option);
|
||||
if (print_value(print_context, JS::PrimitiveString::create(date_time_format.vm(), name), seen_objects).is_error())
|
||||
if (print_value(print_context, JS::PrimitiveString::create(date_time_format.vm(), move(name)), seen_objects).is_error())
|
||||
return JS::throw_completion(JS::js_null());
|
||||
}
|
||||
|
||||
|
|
@ -788,10 +801,10 @@ ErrorOr<void> print_intl_duration_format(JS::PrintContext& print_context, JS::In
|
|||
auto display = JS::Intl::DurationFormat::display_to_string(options.display);
|
||||
|
||||
TRY(js_out(print_context, "\n {}: ", style_name));
|
||||
TRY(print_value(print_context, JS::PrimitiveString::create(duration_format.vm(), style), seen_objects));
|
||||
TRY(print_value(print_context, JS::PrimitiveString::create(duration_format.vm(), move(style)), seen_objects));
|
||||
|
||||
TRY(js_out(print_context, "\n {}: ", display_name));
|
||||
TRY(print_value(print_context, JS::PrimitiveString::create(duration_format.vm(), display), seen_objects));
|
||||
TRY(print_value(print_context, JS::PrimitiveString::create(duration_format.vm(), move(display)), seen_objects));
|
||||
|
||||
return {};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -12,11 +12,19 @@
|
|||
#include <LibJS/Export.h>
|
||||
#include <LibJS/Runtime/Value.h>
|
||||
|
||||
namespace AK {
|
||||
|
||||
class Stream;
|
||||
class Utf16StringBuilder;
|
||||
|
||||
}
|
||||
|
||||
namespace JS {
|
||||
|
||||
struct PrintContext {
|
||||
JS::VM& vm;
|
||||
Stream& stream;
|
||||
AK::Stream* stream { nullptr };
|
||||
AK::Utf16StringBuilder* builder { nullptr };
|
||||
bool strip_ansi { false };
|
||||
bool raw_strings { false };
|
||||
};
|
||||
|
|
|
|||
|
|
@ -702,7 +702,7 @@ ThrowCompletionOr<Value> perform_eval(VM& vm, Value x, CallerMode strict_caller,
|
|||
|
||||
auto rust_compilation = RustIntegration::compile_eval(*code_string, vm, strict_caller, in_function, in_method, in_derived_constructor, in_class_field_initializer);
|
||||
if (!rust_compilation.has_value())
|
||||
return vm.throw_completion<SyntaxError>("Failed to compile eval code"_string);
|
||||
return vm.throw_completion<SyntaxError>("Failed to compile eval code"_utf16);
|
||||
if (rust_compilation->is_error())
|
||||
return vm.throw_completion<SyntaxError>(rust_compilation->release_error());
|
||||
auto& eval_result = rust_compilation->value();
|
||||
|
|
@ -1277,7 +1277,7 @@ CanonicalIndex canonical_numeric_index_string(PropertyKey const& property_key, C
|
|||
|
||||
// FIXME: We return 0 instead of n but it might not observable?
|
||||
// 3. If SameValue(! ToString(n), argument) is true, return n.
|
||||
if (number_to_string(*maybe_double) == argument)
|
||||
if (number_to_utf16_string(*maybe_double) == argument)
|
||||
return CanonicalIndex(CanonicalIndex::Type::Numeric, 0);
|
||||
|
||||
// 4. Return undefined.
|
||||
|
|
@ -1934,7 +1934,7 @@ ThrowCompletionOr<Value> get_option(VM& vm, Object const& options, PropertyKey c
|
|||
[](Empty) -> Value { return js_undefined(); },
|
||||
[](bool default_) -> Value { return Value { default_ }; },
|
||||
[](double default_) -> Value { return Value { default_ }; },
|
||||
[&](StringView default_) -> Value { return PrimitiveString::create(vm, default_); });
|
||||
[&](Utf16View default_) -> Value { return PrimitiveString::create(vm, default_); });
|
||||
}
|
||||
|
||||
// 3. If type is BOOLEAN, then
|
||||
|
|
@ -1960,8 +1960,6 @@ ThrowCompletionOr<Value> get_option(VM& vm, Object const& options, PropertyKey c
|
|||
auto it = find_if(values.begin(), values.end(), [&](auto allowed_value) { return value_string == allowed_value; });
|
||||
if (it == values.end())
|
||||
return vm.throw_completion<RangeError>(ErrorType::OptionIsNotValidValue, value_string, property.as_string());
|
||||
|
||||
value = PrimitiveString::create(vm, *it);
|
||||
}
|
||||
|
||||
// 6. Return value.
|
||||
|
|
@ -1975,7 +1973,8 @@ ThrowCompletionOr<RoundingMode> get_rounding_mode_option(VM& vm, Object const& o
|
|||
static constexpr auto allowed_strings = to_array({ "ceil"sv, "floor"sv, "expand"sv, "trunc"sv, "halfCeil"sv, "halfFloor"sv, "halfExpand"sv, "halfTrunc"sv, "halfEven"sv });
|
||||
|
||||
// 2. Let stringFallback be the value from the "String Identifier" column of the row with fallback in its "Rounding Mode" column.
|
||||
auto string_fallback = allowed_strings[to_underlying(fallback)];
|
||||
static constexpr auto utf16_allowed_strings = to_array({ u"ceil"sv, u"floor"sv, u"expand"sv, u"trunc"sv, u"halfCeil"sv, u"halfFloor"sv, u"halfExpand"sv, u"halfTrunc"sv, u"halfEven"sv });
|
||||
auto string_fallback = utf16_allowed_strings[to_underlying(fallback)];
|
||||
|
||||
// 3. Let stringValue be ? GetOption(options, "roundingMode", STRING, allowedStrings, stringFallback).
|
||||
auto string_value = TRY(get_option(vm, options, vm.names.roundingMode, OptionType::String, allowed_strings, string_fallback));
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <AK/HashTable.h>
|
||||
#include <AK/NonnullRefPtr.h>
|
||||
#include <AK/Utf16FlyString.h>
|
||||
#include <AK/Utf16View.h>
|
||||
#include <LibCrypto/Forward.h>
|
||||
#include <LibGC/RootVector.h>
|
||||
#include <LibJS/Export.h>
|
||||
|
|
@ -375,7 +376,7 @@ enum class OptionType {
|
|||
};
|
||||
|
||||
struct Required { };
|
||||
using OptionDefault = Variant<Required, Empty, bool, StringView, double>;
|
||||
using OptionDefault = Variant<Required, Empty, bool, Utf16View, double>;
|
||||
|
||||
ThrowCompletionOr<GC::Ref<Object>> get_options_object(VM&, Value options);
|
||||
ThrowCompletionOr<Value> get_option(VM&, Object const& options, PropertyKey const& property, OptionType type, ReadonlySpan<StringView> values, OptionDefault const&);
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@ void AggregateErrorPrototype::initialize(Realm& realm)
|
|||
auto& vm = this->vm();
|
||||
Base::initialize(realm);
|
||||
u8 attr = Attribute::Writable | Attribute::Configurable;
|
||||
define_direct_property(vm.names.name, PrimitiveString::create(vm, "AggregateError"_string), attr);
|
||||
define_direct_property(vm.names.message, PrimitiveString::create(vm, String {}), attr);
|
||||
define_direct_property(vm.names.name, PrimitiveString::create(vm, "AggregateError"_utf16_fly_string), attr);
|
||||
define_direct_property(vm.names.message, PrimitiveString::create(vm, Utf16String {}), attr);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ void ArrayIteratorPrototype::initialize(Realm& realm)
|
|||
define_native_function(realm, vm.names.next, next, 0, Attribute::Configurable | Attribute::Writable, Bytecode::Builtin::ArrayIteratorPrototypeNext);
|
||||
|
||||
// 23.1.5.2.2 %ArrayIteratorPrototype% [ @@toStringTag ], https://tc39.es/ecma262/#sec-%arrayiteratorprototype%-@@tostringtag
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Array Iterator"_string), Attribute::Configurable);
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Array Iterator"_utf16_fly_string), Attribute::Configurable);
|
||||
}
|
||||
|
||||
// 23.1.5.2.1 %ArrayIteratorPrototype%.next ( ), https://tc39.es/ecma262/#sec-%arrayiteratorprototype%.next
|
||||
|
|
|
|||
|
|
@ -924,7 +924,7 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::join)
|
|||
// FWIW: engine262, a "100% spec compliant" ECMA-262 impl, aborts with "too much recursion".
|
||||
// Same applies to Array.prototype.toLocaleString().
|
||||
if (array_join_seen_objects().contains(this_object))
|
||||
return PrimitiveString::create(vm, String {});
|
||||
return PrimitiveString::create(vm, Utf16String {});
|
||||
array_join_seen_objects().set(this_object);
|
||||
ArmedScopeGuard unsee_object_guard = [&] {
|
||||
array_join_seen_objects().remove(this_object);
|
||||
|
|
@ -1809,7 +1809,7 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::to_locale_string)
|
|||
auto this_object = TRY(vm.this_value().to_object(vm));
|
||||
|
||||
if (array_join_seen_objects().contains(this_object))
|
||||
return PrimitiveString::create(vm, String {});
|
||||
return PrimitiveString::create(vm, Utf16String {});
|
||||
array_join_seen_objects().set(this_object);
|
||||
ArmedScopeGuard unsee_object_guard = [&] {
|
||||
array_join_seen_objects().remove(this_object);
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ void AsyncGeneratorPrototype::initialize(Realm& realm)
|
|||
define_native_function(realm, vm.names.throw_, throw_, 1, attr);
|
||||
|
||||
// 27.6.1.5 AsyncGenerator.prototype [ @@toStringTag ], https://tc39.es/ecma262/#sec-asyncgenerator-prototype-tostringtag
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "AsyncGenerator"_string), Attribute::Configurable);
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "AsyncGenerator"_utf16_fly_string), Attribute::Configurable);
|
||||
}
|
||||
|
||||
// 27.6.3.3 AsyncGeneratorValidate ( generator, generatorBrand ), https://tc39.es/ecma262/#sec-asyncgeneratorvalidate
|
||||
|
|
|
|||
|
|
@ -248,7 +248,7 @@ void AtomicsObject::initialize(Realm& realm)
|
|||
define_native_function(realm, vm.names.xor_, xor_, 3, attr);
|
||||
|
||||
// 25.4.17 Atomics [ @@toStringTag ], https://tc39.es/ecma262/#sec-atomics-@@tostringtag
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Atomics"_string), Attribute::Configurable);
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Atomics"_utf16_fly_string), Attribute::Configurable);
|
||||
}
|
||||
|
||||
// 25.4.4 Atomics.add ( typedArray, index, value ), https://tc39.es/ecma262/#sec-atomics.add
|
||||
|
|
|
|||
|
|
@ -23,14 +23,9 @@ BigInt::BigInt(Crypto::SignedBigInteger big_integer)
|
|||
{
|
||||
}
|
||||
|
||||
ErrorOr<String> BigInt::to_string() const
|
||||
{
|
||||
return String::formatted("{}n", TRY(m_big_integer.to_base(10)));
|
||||
}
|
||||
|
||||
Utf16String BigInt::to_utf16_string() const
|
||||
{
|
||||
return Utf16String::formatted("{}n", MUST(m_big_integer.to_base(10)));
|
||||
return Utf16String::formatted("{}n", MUST(m_big_integer.to_base_utf16(10)));
|
||||
}
|
||||
|
||||
size_t BigInt::external_memory_size() const
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ public:
|
|||
|
||||
Crypto::SignedBigInteger const& big_integer() const { return m_big_integer; }
|
||||
|
||||
ErrorOr<String> to_string() const;
|
||||
Utf16String to_utf16_string() const;
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ JS_DEFINE_NATIVE_FUNCTION(BigIntPrototype::to_string)
|
|||
}
|
||||
|
||||
// 5. Return BigInt::toString(x, radixMV).
|
||||
return PrimitiveString::create(vm, TRY_OR_THROW_OOM(vm, bigint->big_integer().to_base(radix)));
|
||||
return PrimitiveString::create(vm, TRY_OR_THROW_OOM(vm, bigint->big_integer().to_base_utf16(radix)));
|
||||
}
|
||||
|
||||
// 21.2.3.2 BigInt.prototype.toLocaleString ( [ reserved1 [ , reserved2 ] ] ), https://tc39.es/ecma262/#sec-bigint.prototype.tolocalestring
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ JS_DEFINE_NATIVE_FUNCTION(BooleanPrototype::to_string)
|
|||
auto b = TRY(this_boolean_value(vm, vm.this_value()));
|
||||
|
||||
// 2. If b is true, return "true"; else return "false".
|
||||
return PrimitiveString::create(vm, TRY_OR_THROW_OOM(vm, String::from_utf8(b ? "true"sv : "false"sv)));
|
||||
return PrimitiveString::create(vm, b ? "true"_utf16 : "false"_utf16);
|
||||
}
|
||||
|
||||
// 20.3.3.3 Boolean.prototype.valueOf ( ), https://tc39.es/ecma262/#sec-boolean.prototype.valueof
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ void ConsoleObject::initialize(Realm& realm)
|
|||
define_native_function(realm, vm.names.timeLog, time_log, 0, attr);
|
||||
define_native_function(realm, vm.names.timeEnd, time_end, 0, attr);
|
||||
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "console"_string), Attribute::Configurable);
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "console"_utf16_fly_string), Attribute::Configurable);
|
||||
}
|
||||
|
||||
// 1.1.1. assert(condition, ...data), https://console.spec.whatwg.org/#assert
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ Date::Date(double date_value, Object& prototype)
|
|||
|
||||
Date::~Date() = default;
|
||||
|
||||
ErrorOr<Utf16String> Date::iso_date_string() const
|
||||
Utf16String Date::iso_date_string() const
|
||||
{
|
||||
int year = year_from_time(m_date_value);
|
||||
|
||||
|
|
@ -442,14 +442,18 @@ Unicode::TimeZoneOffset get_named_time_zone_offset_milliseconds(StringView time_
|
|||
return offset.release_value();
|
||||
}
|
||||
|
||||
static Optional<String> cached_system_time_zone_identifier;
|
||||
static auto& cached_system_time_zone_identifier()
|
||||
{
|
||||
static NeverDestroyed<Optional<Utf16String>> cached_system_time_zone_identifier;
|
||||
return *cached_system_time_zone_identifier;
|
||||
}
|
||||
|
||||
// 21.4.1.24 SystemTimeZoneIdentifier ( ), https://tc39.es/ecma262/#sec-systemtimezoneidentifier
|
||||
String system_time_zone_identifier()
|
||||
Utf16String system_time_zone_identifier()
|
||||
{
|
||||
// OPTIMIZATION: We cache the system time zone to avoid the expensive lookups below.
|
||||
if (cached_system_time_zone_identifier.has_value())
|
||||
return *cached_system_time_zone_identifier;
|
||||
if (cached_system_time_zone_identifier().has_value())
|
||||
return *cached_system_time_zone_identifier();
|
||||
|
||||
// 1. If the implementation only supports the UTC time zone, return "UTC".
|
||||
|
||||
|
|
@ -457,23 +461,22 @@ String system_time_zone_identifier()
|
|||
// time zone identifier or an offset time zone identifier.
|
||||
auto system_time_zone_string = Unicode::current_time_zone();
|
||||
|
||||
auto utf16_system_time_zone_string = Utf16String::from_utf8(system_time_zone_string);
|
||||
if (!is_offset_time_zone_identifier(utf16_system_time_zone_string)) {
|
||||
if (!is_offset_time_zone_identifier(system_time_zone_string)) {
|
||||
auto time_zone_identifier = Intl::get_available_named_time_zone_identifier(system_time_zone_string);
|
||||
if (!time_zone_identifier.has_value())
|
||||
return "UTC"_string;
|
||||
return "UTC"_utf16;
|
||||
|
||||
system_time_zone_string = time_zone_identifier->primary_identifier;
|
||||
}
|
||||
|
||||
// 3. Return systemTimeZoneString.
|
||||
cached_system_time_zone_identifier = move(system_time_zone_string);
|
||||
return *cached_system_time_zone_identifier;
|
||||
cached_system_time_zone_identifier() = move(system_time_zone_string);
|
||||
return *cached_system_time_zone_identifier();
|
||||
}
|
||||
|
||||
void clear_system_time_zone_cache()
|
||||
{
|
||||
cached_system_time_zone_identifier.clear();
|
||||
cached_system_time_zone_identifier().clear();
|
||||
}
|
||||
|
||||
// 21.4.1.25 LocalTime ( t ), https://tc39.es/ecma262/#sec-localtime
|
||||
|
|
@ -484,7 +487,7 @@ double local_time(double time)
|
|||
auto system_time_zone_identifier = JS::system_time_zone_identifier();
|
||||
|
||||
// 2. Let parseResult be ! ParseTimeZoneIdentifier(systemTimeZoneIdentifier).
|
||||
auto parse_result = Temporal::parse_time_zone_identifier(system_time_zone_identifier);
|
||||
auto parse_result = Temporal::parse_time_zone_identifier(system_time_zone_identifier.utf16_view());
|
||||
|
||||
double offset_nanoseconds { 0 };
|
||||
|
||||
|
|
@ -496,7 +499,7 @@ double local_time(double time)
|
|||
// 4. Else,
|
||||
else {
|
||||
// a. Let offsetNs be GetNamedTimeZoneOffsetNanoseconds(systemTimeZoneIdentifier, ℤ(ℝ(t) × 10^6)).
|
||||
auto offset = get_named_time_zone_offset_milliseconds(system_time_zone_identifier, time);
|
||||
auto offset = get_named_time_zone_offset_milliseconds(system_time_zone_identifier.utf16_view().bytes(), time);
|
||||
offset_nanoseconds = static_cast<double>(offset.offset.to_nanoseconds());
|
||||
}
|
||||
|
||||
|
|
@ -515,7 +518,7 @@ double utc_time(double time)
|
|||
auto system_time_zone_identifier = JS::system_time_zone_identifier();
|
||||
|
||||
// 2. Let parseResult be ! ParseTimeZoneIdentifier(systemTimeZoneIdentifier).
|
||||
auto parse_result = Temporal::parse_time_zone_identifier(system_time_zone_identifier);
|
||||
auto parse_result = Temporal::parse_time_zone_identifier(system_time_zone_identifier.utf16_view());
|
||||
|
||||
double offset_nanoseconds { 0 };
|
||||
|
||||
|
|
@ -530,7 +533,7 @@ double utc_time(double time)
|
|||
auto iso_date_time = Temporal::time_value_to_iso_date_time_record(time);
|
||||
|
||||
// b. Let possibleInstants be GetNamedTimeZoneEpochNanoseconds(systemTimeZoneIdentifier, isoDateTime).
|
||||
auto possible_instants = get_named_time_zone_epoch_nanoseconds(system_time_zone_identifier, iso_date_time);
|
||||
auto possible_instants = get_named_time_zone_epoch_nanoseconds(system_time_zone_identifier.utf16_view().bytes(), iso_date_time);
|
||||
|
||||
// c. NOTE: The following steps ensure that when t represents local time repeating multiple times at a negative
|
||||
// time zone transition (e.g. when the daylight saving time ends or the time zone offset is decreased due to
|
||||
|
|
@ -565,7 +568,7 @@ double utc_time(double time)
|
|||
}
|
||||
|
||||
// f. Let offsetNs be GetNamedTimeZoneOffsetNanoseconds(systemTimeZoneIdentifier, disambiguatedInstant).
|
||||
auto offset = get_named_time_zone_offset_nanoseconds(system_time_zone_identifier, disambiguated_instant);
|
||||
auto offset = get_named_time_zone_offset_nanoseconds(system_time_zone_identifier.utf16_view().bytes(), disambiguated_instant);
|
||||
offset_nanoseconds = static_cast<double>(offset.offset.to_nanoseconds());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Utf16String.h>
|
||||
#include <AK/Utf16View.h>
|
||||
#include <LibCrypto/BigInt/SignedBigInteger.h>
|
||||
#include <LibJS/Export.h>
|
||||
|
|
@ -28,7 +29,7 @@ public:
|
|||
double date_value() const { return m_date_value; }
|
||||
void set_date_value(double value) { m_date_value = value; }
|
||||
|
||||
ErrorOr<Utf16String> iso_date_string() const;
|
||||
Utf16String iso_date_string() const;
|
||||
|
||||
private:
|
||||
Date(double date_value, Object& prototype);
|
||||
|
|
@ -43,8 +44,8 @@ inline bool Object::fast_is<Date>() const { return is_date(); }
|
|||
|
||||
// 21.4.1.22 Time Zone Identifier Record, https://tc39.es/ecma262/#sec-time-zone-identifier-record
|
||||
struct TimeZoneIdentifier {
|
||||
String identifier; // [[Identifier]]
|
||||
String primary_identifier; // [[PrimaryIdentifier]]
|
||||
Utf16String identifier; // [[Identifier]]
|
||||
Utf16String primary_identifier; // [[PrimaryIdentifier]]
|
||||
};
|
||||
|
||||
// https://tc39.es/ecma262/#eqn-HoursPerDay
|
||||
|
|
@ -90,7 +91,7 @@ i64 clip_double_to_sane_time(double value);
|
|||
Vector<Crypto::SignedBigInteger> get_named_time_zone_epoch_nanoseconds(StringView time_zone_identifier, Temporal::ISODateTime const&);
|
||||
Unicode::TimeZoneOffset get_named_time_zone_offset_nanoseconds(StringView time_zone_identifier, Crypto::SignedBigInteger const& epoch_nanoseconds);
|
||||
Unicode::TimeZoneOffset get_named_time_zone_offset_milliseconds(StringView time_zone_identifier, double epoch_milliseconds);
|
||||
String system_time_zone_identifier();
|
||||
Utf16String system_time_zone_identifier();
|
||||
JS_API void clear_system_time_zone_cache();
|
||||
double local_time(double time);
|
||||
double utc_time(double time);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/ByteString.h>
|
||||
#include <AK/DateConstants.h>
|
||||
#include <AK/Function.h>
|
||||
#include <AK/TypeCasts.h>
|
||||
|
|
@ -955,11 +954,12 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::to_date_string)
|
|||
|
||||
// 3. If tv is NaN, return "Invalid Date".
|
||||
if (isnan(time))
|
||||
return PrimitiveString::create(vm, "Invalid Date"_string);
|
||||
return PrimitiveString::create(vm, "Invalid Date"_utf16_fly_string);
|
||||
|
||||
// 4. Let t be LocalTime(tv).
|
||||
// 5. Return DateString(t).
|
||||
return PrimitiveString::create(vm, date_string(local_time(time)));
|
||||
auto string = date_string(local_time(time));
|
||||
return PrimitiveString::create(vm, move(string));
|
||||
}
|
||||
|
||||
// 21.4.4.36 Date.prototype.toISOString ( ), https://tc39.es/ecma262/#sec-date.prototype.toisostring
|
||||
|
|
@ -970,7 +970,7 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::to_iso_string)
|
|||
if (!Value(this_object->date_value()).is_finite_number())
|
||||
return vm.throw_completion<RangeError>(ErrorType::InvalidTimeValue);
|
||||
|
||||
auto string = TRY_OR_THROW_OOM(vm, this_object->iso_date_string());
|
||||
auto string = this_object->iso_date_string();
|
||||
return PrimitiveString::create(vm, move(string));
|
||||
}
|
||||
|
||||
|
|
@ -1001,7 +1001,7 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::to_locale_date_string)
|
|||
|
||||
// 2. If x is NaN, return "Invalid Date".
|
||||
if (isnan(time))
|
||||
return PrimitiveString::create(vm, "Invalid Date"_string);
|
||||
return PrimitiveString::create(vm, "Invalid Date"_utf16_fly_string);
|
||||
|
||||
// 3. Let dateFormat be ? CreateDateTimeFormat(%DateTimeFormat%, locales, options, "date", "date").
|
||||
auto date_format = TRY(Intl::create_date_time_format(vm, realm.intrinsics().intl_date_time_format_constructor(), locales, options, Intl::OptionRequired::Date, Intl::OptionDefaults::Date));
|
||||
|
|
@ -1025,7 +1025,7 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::to_locale_string)
|
|||
|
||||
// 2. If x is NaN, return "Invalid Date".
|
||||
if (isnan(time))
|
||||
return PrimitiveString::create(vm, "Invalid Date"_string);
|
||||
return PrimitiveString::create(vm, "Invalid Date"_utf16_fly_string);
|
||||
|
||||
// 3. Let dateFormat be ? CreateDateTimeFormat(%DateTimeFormat%, locales, options, "any", "all").
|
||||
auto date_format = TRY(Intl::create_date_time_format(vm, realm.intrinsics().intl_date_time_format_constructor(), locales, options, Intl::OptionRequired::Any, Intl::OptionDefaults::All));
|
||||
|
|
@ -1049,7 +1049,7 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::to_locale_time_string)
|
|||
|
||||
// 2. If x is NaN, return "Invalid Date".
|
||||
if (isnan(time))
|
||||
return PrimitiveString::create(vm, "Invalid Date"_string);
|
||||
return PrimitiveString::create(vm, "Invalid Date"_utf16_fly_string);
|
||||
|
||||
// 3. Let timeFormat be ? CreateDateTimeFormat(%DateTimeFormat%, locales, options, "time", "time").
|
||||
auto time_format = TRY(Intl::create_date_time_format(vm, realm.intrinsics().intl_date_time_format_constructor(), locales, options, Intl::OptionRequired::Time, Intl::OptionDefaults::Time));
|
||||
|
|
@ -1071,17 +1071,17 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::to_string)
|
|||
|
||||
// 21.4.4.41.1 TimeString ( tv ), https://tc39.es/ecma262/#sec-timestring
|
||||
// 14.5.8 TimeString ( tv ), https://tc39.es/proposal-temporal/#sec-timestring
|
||||
ByteString time_string(double time)
|
||||
Utf16String time_string(double time)
|
||||
{
|
||||
// 1. Let timeString be FormatTimeString(ℝ(HourFromTime(tv)), ℝ(MinFromTime(tv)), ℝ(SecFromTime(tv)), 0, 0).
|
||||
auto time_string = Temporal::format_time_string(hour_from_time(time), min_from_time(time), sec_from_time(time), 0, 0);
|
||||
|
||||
// 4. Return the string-concatenation of timeString, the code unit 0x0020 (SPACE), and "GMT".
|
||||
return ByteString::formatted("{} GMT", time_string);
|
||||
return Utf16String::formatted("{} GMT", time_string);
|
||||
}
|
||||
|
||||
// 21.4.4.41.2 DateString ( tv ), https://tc39.es/ecma262/#sec-datestring
|
||||
ByteString date_string(double time)
|
||||
Utf16String date_string(double time)
|
||||
{
|
||||
// 1. Let weekday be the Name of the entry in Table 62 with the Number WeekDay(tv).
|
||||
auto weekday = short_day_names[week_day(time)];
|
||||
|
|
@ -1100,7 +1100,7 @@ ByteString date_string(double time)
|
|||
|
||||
// 6. Let paddedYear be ToZeroPaddedDecimalString(abs(ℝ(yv)), 4).
|
||||
// 7. Return the string-concatenation of weekday, the code unit 0x0020 (SPACE), month, the code unit 0x0020 (SPACE), day, the code unit 0x0020 (SPACE), yearSign, and paddedYear.
|
||||
return ByteString::formatted("{} {} {:02} {}{:04}", weekday, month, day, year_sign, abs(year));
|
||||
return Utf16String::formatted("{} {} {:02} {}{:04}", weekday, month, day, year_sign, abs(year));
|
||||
}
|
||||
|
||||
// 21.4.4.41.3 TimeZoneString ( tv ), https://tc39.es/ecma262/#sec-timezoneestring
|
||||
|
|
@ -1111,13 +1111,13 @@ Utf16String time_zone_string(double time)
|
|||
auto system_time_zone_identifier = JS::system_time_zone_identifier();
|
||||
|
||||
// 2. Let offsetMinutes be ! ParseTimeZoneIdentifier(systemTimeZoneIdentifier).[[OffsetMinutes]].
|
||||
auto offset_minutes = Temporal::parse_time_zone_identifier(system_time_zone_identifier).offset_minutes;
|
||||
auto offset_minutes = Temporal::parse_time_zone_identifier(system_time_zone_identifier.utf16_view()).offset_minutes;
|
||||
auto in_dst = Unicode::TimeZoneOffset::InDST::No;
|
||||
|
||||
// 2. If offsetMinutes is EMPTY, then
|
||||
if (!offset_minutes.has_value()) {
|
||||
// a. Let offsetNs be GetNamedTimeZoneOffsetNanoseconds(systemTimeZoneIdentifier, ℤ(ℝ(tv) × 10^6)).
|
||||
auto offset = get_named_time_zone_offset_milliseconds(system_time_zone_identifier, time);
|
||||
auto offset = get_named_time_zone_offset_milliseconds(system_time_zone_identifier.utf16_view().bytes(), time);
|
||||
in_dst = offset.in_dst;
|
||||
|
||||
// b. Set offsetMinutes to truncate(offsetNs / (60 × 10**9)).
|
||||
|
|
@ -1130,11 +1130,10 @@ Utf16String time_zone_string(double time)
|
|||
// 5. Let tzName be an implementation-defined string that is either the empty String or the string-concatenation of
|
||||
// the code unit 0x0020 (SPACE), the code unit 0x0028 (LEFT PARENTHESIS), an implementation-defined timezone name,
|
||||
// and the code unit 0x0029 (RIGHT PARENTHESIS).
|
||||
auto time_zone_identifier = Unicode::current_time_zone();
|
||||
auto tz_name = Utf16String::from_utf8(time_zone_identifier);
|
||||
auto tz_name = Unicode::current_time_zone();
|
||||
|
||||
// Most implementations seem to prefer the long-form display name of the time zone. Not super important, but we may as well match that behavior.
|
||||
if (auto name = Unicode::time_zone_display_name(Unicode::default_locale(), time_zone_identifier, in_dst, time); name.has_value())
|
||||
if (auto name = Unicode::time_zone_display_name(Unicode::default_locale().bytes(), tz_name.utf16_view().bytes(), in_dst, time); name.has_value())
|
||||
tz_name = name.release_value();
|
||||
|
||||
// 10. Return the string-concatenation of offsetString and tzName.
|
||||
|
|
@ -1164,7 +1163,7 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::to_time_string)
|
|||
|
||||
// 3. If tv is NaN, return "Invalid Date".
|
||||
if (isnan(time))
|
||||
return PrimitiveString::create(vm, "Invalid Date"_string);
|
||||
return PrimitiveString::create(vm, "Invalid Date"_utf16_fly_string);
|
||||
|
||||
// 4. Let t be LocalTime(tv).
|
||||
// 5. Return the string-concatenation of TimeString(t) and TimeZoneString(tv).
|
||||
|
|
@ -1181,7 +1180,7 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::to_utc_string)
|
|||
|
||||
// 3. If tv is NaN, return "Invalid Date".
|
||||
if (isnan(time))
|
||||
return PrimitiveString::create(vm, "Invalid Date"_string);
|
||||
return PrimitiveString::create(vm, "Invalid Date"_utf16_fly_string);
|
||||
|
||||
// 4. Let weekday be the Name of the entry in Table 62 with the Number WeekDay(tv).
|
||||
auto weekday = short_day_names[week_day(time)];
|
||||
|
|
@ -1200,7 +1199,7 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::to_utc_string)
|
|||
|
||||
// 9. Let paddedYear be ToZeroPaddedDecimalString(abs(ℝ(yv)), 4).
|
||||
// 10. Return the string-concatenation of weekday, ",", the code unit 0x0020 (SPACE), day, the code unit 0x0020 (SPACE), month, the code unit 0x0020 (SPACE), yearSign, paddedYear, the code unit 0x0020 (SPACE), and TimeString(tv).
|
||||
auto string = ByteString::formatted("{}, {:02} {} {}{:04} {}", weekday, day, month, year_sign, abs(year), time_string(time));
|
||||
auto string = Utf16String::formatted("{}, {:02} {} {}{:04} {}", weekday, day, month, year_sign, abs(year), time_string(time));
|
||||
return PrimitiveString::create(vm, move(string));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -76,8 +76,8 @@ private:
|
|||
};
|
||||
|
||||
ThrowCompletionOr<double> this_time_value(VM&, Value value);
|
||||
ByteString time_string(double time);
|
||||
ByteString date_string(double time);
|
||||
Utf16String time_string(double time);
|
||||
Utf16String date_string(double time);
|
||||
Utf16String time_zone_string(double time);
|
||||
Utf16String to_date_string(double time);
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,13 @@ GC::Ref<Error> Error::create(Realm& realm, Utf16String message)
|
|||
return error;
|
||||
}
|
||||
|
||||
GC::Ref<Error> Error::create(Realm& realm, Utf16View message)
|
||||
{
|
||||
auto error = Error::create(realm);
|
||||
error->set_message(message);
|
||||
return error;
|
||||
}
|
||||
|
||||
GC::Ref<Error> Error::create(Realm& realm, StringView message)
|
||||
{
|
||||
return create(realm, Utf16String::from_utf8(message));
|
||||
|
|
@ -78,6 +85,14 @@ void Error::set_message(Utf16String message)
|
|||
define_direct_property(vm.names.message, PrimitiveString::create(vm, move(message)), attr);
|
||||
}
|
||||
|
||||
void Error::set_message(Utf16View message)
|
||||
{
|
||||
auto& vm = this->vm();
|
||||
|
||||
u8 attr = Attribute::Writable | Attribute::Configurable;
|
||||
define_direct_property(vm.names.message, PrimitiveString::create(vm, message), attr);
|
||||
}
|
||||
|
||||
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
|
||||
GC_DEFINE_ALLOCATOR(ClassName); \
|
||||
GC::Ref<ClassName> ClassName::create(Realm& realm) \
|
||||
|
|
@ -92,6 +107,13 @@ void Error::set_message(Utf16String message)
|
|||
return error; \
|
||||
} \
|
||||
\
|
||||
GC::Ref<ClassName> ClassName::create(Realm& realm, Utf16View message) \
|
||||
{ \
|
||||
auto error = ClassName::create(realm); \
|
||||
error->set_message(message); \
|
||||
return error; \
|
||||
} \
|
||||
\
|
||||
GC::Ref<ClassName> ClassName::create(Realm& realm, StringView message) \
|
||||
{ \
|
||||
return create(realm, Utf16String::from_utf8(message)); \
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ class JS_API Error
|
|||
public:
|
||||
static GC::Ref<Error> create(Realm&);
|
||||
static GC::Ref<Error> create(Realm&, Utf16String message);
|
||||
static GC::Ref<Error> create(Realm&, Utf16View message);
|
||||
static GC::Ref<Error> create(Realm&, StringView message);
|
||||
|
||||
virtual ~Error() override = default;
|
||||
|
|
@ -35,6 +36,7 @@ public:
|
|||
ThrowCompletionOr<void> install_error_cause(Value options);
|
||||
|
||||
void set_message(Utf16String);
|
||||
void set_message(Utf16View);
|
||||
|
||||
protected:
|
||||
explicit Error(Object& prototype);
|
||||
|
|
@ -62,6 +64,7 @@ inline bool Object::fast_is<Error>() const { return is_error_object(); }
|
|||
public: \
|
||||
static GC::Ref<ClassName> create(Realm&); \
|
||||
static GC::Ref<ClassName> create(Realm&, Utf16String message); \
|
||||
static GC::Ref<ClassName> create(Realm&, Utf16View message); \
|
||||
static GC::Ref<ClassName> create(Realm&, StringView message); \
|
||||
\
|
||||
explicit ClassName(Object& prototype); \
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ void ErrorPrototype::initialize(Realm& realm)
|
|||
auto& vm = this->vm();
|
||||
Base::initialize(realm);
|
||||
u8 attr = Attribute::Writable | Attribute::Configurable;
|
||||
define_direct_property(vm.names.name, PrimitiveString::create(vm, "Error"_string), attr);
|
||||
define_direct_property(vm.names.name, PrimitiveString::create(vm, "Error"_utf16_fly_string), attr);
|
||||
define_direct_property(vm.names.message, PrimitiveString::create(vm, Utf16String {}), attr);
|
||||
define_native_function(realm, vm.names.toString, to_string, 0, attr);
|
||||
// Non standard property "stack"
|
||||
|
|
@ -144,7 +144,7 @@ JS_DEFINE_NATIVE_FUNCTION(ErrorPrototype::stack_setter)
|
|||
auto& vm = this->vm(); \
|
||||
Base::initialize(realm); \
|
||||
u8 attr = Attribute::Writable | Attribute::Configurable; \
|
||||
define_direct_property(vm.names.name, PrimitiveString::create(vm, #ClassName##_string), attr); \
|
||||
define_direct_property(vm.names.name, PrimitiveString::create(vm, #ClassName##_utf16_fly_string), attr); \
|
||||
define_direct_property(vm.names.message, PrimitiveString::create(vm, Utf16String {}), attr); \
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,15 +9,8 @@
|
|||
namespace JS {
|
||||
|
||||
#define __ENUMERATE_JS_ERROR(name, message) \
|
||||
ErrorType const& ErrorType::name = *new ErrorType(message##sv);
|
||||
ErrorType const& ErrorType::name = *new ErrorType(message##sv, Utf16View { message##sv });
|
||||
JS_ENUMERATE_ERROR_TYPES(__ENUMERATE_JS_ERROR)
|
||||
#undef __ENUMERATE_JS_ERROR
|
||||
|
||||
Utf16String const& ErrorType::message() const
|
||||
{
|
||||
if (m_message.is_empty())
|
||||
m_message = Utf16String::from_utf8_without_validation(m_format);
|
||||
return m_message;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <AK/StringView.h>
|
||||
#include <AK/Utf16String.h>
|
||||
#include <AK/Utf16View.h>
|
||||
#include <LibJS/Export.h>
|
||||
|
||||
#define JS_ENUMERATE_ERROR_TYPES(M) \
|
||||
|
|
@ -320,16 +321,17 @@ public:
|
|||
#undef __ENUMERATE_JS_ERROR
|
||||
|
||||
StringView format() const { return m_format; }
|
||||
Utf16String const& message() const;
|
||||
Utf16View message() const { return m_message; }
|
||||
|
||||
private:
|
||||
explicit ErrorType(StringView format)
|
||||
explicit ErrorType(StringView format, Utf16View message)
|
||||
: m_format(format)
|
||||
, m_message(message)
|
||||
{
|
||||
}
|
||||
|
||||
StringView m_format;
|
||||
mutable Utf16String m_message;
|
||||
Utf16View m_message;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ ThrowCompletionOr<GC::Ref<ECMAScriptFunctionObject>> FunctionConstructor::create
|
|||
|
||||
auto rust_compilation = RustIntegration::compile_dynamic_function(vm, source_text, parameters_string, body_parse_string, kind);
|
||||
if (!rust_compilation.has_value())
|
||||
return vm.throw_completion<SyntaxError>("Failed to compile dynamic function"_string);
|
||||
return vm.throw_completion<SyntaxError>("Failed to compile dynamic function"_utf16);
|
||||
if (rust_compilation->is_error())
|
||||
return vm.throw_completion<SyntaxError>(rust_compilation->release_error());
|
||||
function_data = rust_compilation->value();
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ void FunctionPrototype::initialize(Realm& realm)
|
|||
define_native_function(realm, vm.names.toString, to_string, 0, attr);
|
||||
define_native_function(realm, vm.well_known_symbol_has_instance(), symbol_has_instance, 1, 0, Bytecode::Builtin::OrdinaryHasInstance);
|
||||
define_direct_property(vm.names.length, Value(0), Attribute::Configurable);
|
||||
define_direct_property(vm.names.name, PrimitiveString::create(vm, String {}), Attribute::Configurable);
|
||||
define_direct_property(vm.names.name, PrimitiveString::create(vm, Utf16String {}), Attribute::Configurable);
|
||||
}
|
||||
|
||||
ThrowCompletionOr<Value> FunctionPrototype::internal_call(ExecutionContext&, Value)
|
||||
|
|
@ -214,12 +214,12 @@ JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::to_string)
|
|||
if (auto const* native_function = as_if<NativeFunction>(function)) {
|
||||
// NOTE: once we remove name(), the fallback here can simply be an empty string.
|
||||
auto const name = native_function->initial_name().value_or(native_function->name());
|
||||
return PrimitiveString::create(vm, ByteString::formatted("function {}() {{ [native code] }}", name));
|
||||
return PrimitiveString::create(vm, Utf16String::formatted("function {}() {{ [native code] }}", name));
|
||||
}
|
||||
|
||||
// 4. If Type(func) is Object and IsCallable(func) is true, return an implementation-defined String source code representation of func. The representation must have the syntax of a NativeFunction.
|
||||
// NOTE: ProxyObject, BoundFunction, WrappedFunction
|
||||
return PrimitiveString::create(vm, "function () { [native code] }"_string);
|
||||
return PrimitiveString::create(vm, "function () { [native code] }"_utf16_fly_string);
|
||||
}
|
||||
|
||||
// 20.2.3.6 Function.prototype [ @@hasInstance ] ( V ), https://tc39.es/ecma262/#sec-function.prototype-@@hasinstance
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ void GeneratorFunctionPrototype::initialize(Realm& realm)
|
|||
// 27.3.3.2 GeneratorFunction.prototype.prototype, https://tc39.es/ecma262/#sec-generatorfunction.prototype.prototype
|
||||
define_direct_property(vm.names.prototype, realm.intrinsics().generator_prototype(), Attribute::Configurable);
|
||||
// 27.3.3.3 GeneratorFunction.prototype [ @@toStringTag ], https://tc39.es/ecma262/#sec-generatorfunction.prototype-@@tostringtag
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "GeneratorFunction"_string), Attribute::Configurable);
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "GeneratorFunction"_utf16_fly_string), Attribute::Configurable);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ void GeneratorPrototype::initialize(Realm& realm)
|
|||
define_native_function(realm, vm.names.throw_, throw_, 1, attr);
|
||||
|
||||
// 27.5.1.5 Generator.prototype [ @@toStringTag ], https://tc39.es/ecma262/#sec-generator.prototype-@@tostringtag
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Generator"_string), Attribute::Configurable);
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Generator"_utf16_fly_string), Attribute::Configurable);
|
||||
}
|
||||
|
||||
static Value generator_resume_result_to_value(VM& vm, GeneratorObject::IterationResult const& iteration_result)
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <AK/Hex.h>
|
||||
#include <AK/StringConversions.h>
|
||||
#include <AK/UnicodeUtils.h>
|
||||
#include <AK/Utf16StringBuilder.h>
|
||||
#include <AK/Utf16View.h>
|
||||
#include <AK/Utf8View.h>
|
||||
#include <LibGC/DeferGC.h>
|
||||
|
|
@ -366,15 +367,13 @@ JS_DEFINE_NATIVE_FUNCTION(GlobalObject::parse_int)
|
|||
}
|
||||
|
||||
// 19.2.6.5 Encode ( string, extraUnescaped ), https://tc39.es/ecma262/#sec-encode
|
||||
static ThrowCompletionOr<ByteString> encode(VM& vm, ByteString const& string, StringView unescaped_set)
|
||||
static ThrowCompletionOr<Utf16String> encode(VM& vm, Utf16View const& string, StringView unescaped_set)
|
||||
{
|
||||
auto utf16_string = Utf16String::from_utf8(string);
|
||||
|
||||
// 1. Let strLen be the length of string.
|
||||
auto string_length = utf16_string.length_in_code_units();
|
||||
auto string_length = string.length_in_code_units();
|
||||
|
||||
// 2. Let R be the empty String.
|
||||
StringBuilder encoded_builder;
|
||||
StringBuilder encoded_builder(StringBuilder::Mode::UTF16);
|
||||
|
||||
// 3. Let alwaysUnescaped be the string-concatenation of the ASCII word characters and "-.!~*'()".
|
||||
// 4. Let unescapedSet be the string-concatenation of alwaysUnescaped and extraUnescaped.
|
||||
|
|
@ -389,7 +388,7 @@ static ThrowCompletionOr<ByteString> encode(VM& vm, ByteString const& string, St
|
|||
// Handled below
|
||||
|
||||
// b. Let C be the code unit at index k within string.
|
||||
auto code_unit = utf16_string.code_unit_at(k);
|
||||
auto code_unit = string.code_unit_at(k);
|
||||
// c. If C is in unescapedSet, then
|
||||
// NOTE: We assume the unescaped set only contains ascii characters as unescaped_set is a StringView.
|
||||
if (code_unit < 0x80 && unescaped_set.contains(static_cast<char>(code_unit))) {
|
||||
|
|
@ -402,7 +401,7 @@ static ThrowCompletionOr<ByteString> encode(VM& vm, ByteString const& string, St
|
|||
// d. Else,
|
||||
else {
|
||||
// i. Let cp be CodePointAt(string, k).
|
||||
auto code_point = code_point_at(utf16_string, k);
|
||||
auto code_point = code_point_at(string, k);
|
||||
// ii. If cp.[[IsUnpairedSurrogate]] is true, throw a URIError exception.
|
||||
if (code_point.is_unpaired_surrogate)
|
||||
return vm.throw_completion<URIError>(ErrorType::URIMalformed);
|
||||
|
|
@ -420,78 +419,79 @@ static ThrowCompletionOr<ByteString> encode(VM& vm, ByteString const& string, St
|
|||
VERIFY(nwritten > 0);
|
||||
}
|
||||
}
|
||||
return encoded_builder.to_byte_string();
|
||||
return encoded_builder.to_utf16_string();
|
||||
}
|
||||
|
||||
static ThrowCompletionOr<u8> decode_percent_encoded_byte(VM& vm, Utf16View const& string, size_t percent_index)
|
||||
{
|
||||
if (percent_index + 2 >= string.length_in_code_units())
|
||||
return vm.throw_completion<URIError>(ErrorType::URIMalformed);
|
||||
|
||||
auto first_digit = string.code_unit_at(percent_index + 1);
|
||||
if (!is_ascii_hex_digit(first_digit))
|
||||
return vm.throw_completion<URIError>(ErrorType::URIMalformed);
|
||||
|
||||
auto second_digit = string.code_unit_at(percent_index + 2);
|
||||
if (!is_ascii_hex_digit(second_digit))
|
||||
return vm.throw_completion<URIError>(ErrorType::URIMalformed);
|
||||
|
||||
return (parse_ascii_hex_digit(first_digit) << 4) | parse_ascii_hex_digit(second_digit);
|
||||
}
|
||||
|
||||
// 19.2.6.6 Decode ( string, preserveEscapeSet ), https://tc39.es/ecma262/#sec-decode
|
||||
// FIXME: Add spec comments to this implementation. It deviates a lot, so that's a bit tricky.
|
||||
static ThrowCompletionOr<ByteString> decode(VM& vm, ByteString const& string, StringView reserved_set)
|
||||
static ThrowCompletionOr<Utf16String> decode(VM& vm, Utf16View const& string, StringView reserved_set)
|
||||
{
|
||||
StringBuilder decoded_builder;
|
||||
auto code_point_start_offset = 0u;
|
||||
auto expected_continuation_bytes = 0;
|
||||
for (size_t k = 0; k < string.length(); k++) {
|
||||
auto code_unit = string[k];
|
||||
Utf16StringBuilder decoded_builder;
|
||||
for (size_t k = 0; k < string.length_in_code_units(); ++k) {
|
||||
auto code_unit = string.code_unit_at(k);
|
||||
if (code_unit != '%') {
|
||||
if (expected_continuation_bytes > 0)
|
||||
return vm.throw_completion<URIError>(ErrorType::URIMalformed);
|
||||
|
||||
decoded_builder.append(code_unit);
|
||||
decoded_builder.append_code_unit(code_unit);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (k + 2 >= string.length())
|
||||
return vm.throw_completion<URIError>(ErrorType::URIMalformed);
|
||||
|
||||
auto first_digit = decode_hex_digit(string[k + 1]);
|
||||
if (first_digit >= 16)
|
||||
return vm.throw_completion<URIError>(ErrorType::URIMalformed);
|
||||
|
||||
auto second_digit = decode_hex_digit(string[k + 2]);
|
||||
if (second_digit >= 16)
|
||||
return vm.throw_completion<URIError>(ErrorType::URIMalformed);
|
||||
|
||||
u8 decoded_code_unit = (first_digit << 4) | second_digit;
|
||||
auto decoded_code_unit = TRY(decode_percent_encoded_byte(vm, string, k));
|
||||
k += 2;
|
||||
if (expected_continuation_bytes > 0) {
|
||||
decoded_builder.append(decoded_code_unit);
|
||||
expected_continuation_bytes--;
|
||||
if (expected_continuation_bytes == 0 && !Utf8View(decoded_builder.string_view().substring_view(code_point_start_offset)).validate(AllowLonelySurrogates::No))
|
||||
return vm.throw_completion<URIError>(ErrorType::URIMalformed);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (decoded_code_unit < 0x80) {
|
||||
if (reserved_set.contains(static_cast<char>(decoded_code_unit)))
|
||||
decoded_builder.append(string.substring_view(k - 2, 3));
|
||||
else
|
||||
decoded_builder.append(decoded_code_unit);
|
||||
decoded_builder.append_code_unit(decoded_code_unit);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto leading_ones = count_leading_zeroes_safe(static_cast<u8>(~decoded_code_unit));
|
||||
auto leading_ones = static_cast<size_t>(count_leading_zeroes_safe(static_cast<u8>(~decoded_code_unit)));
|
||||
if (leading_ones == 1 || leading_ones > 4)
|
||||
return vm.throw_completion<URIError>(ErrorType::URIMalformed);
|
||||
|
||||
code_point_start_offset = decoded_builder.length();
|
||||
decoded_builder.append(decoded_code_unit);
|
||||
expected_continuation_bytes = leading_ones - 1;
|
||||
}
|
||||
if (expected_continuation_bytes > 0)
|
||||
u8 utf8_bytes[4] { decoded_code_unit };
|
||||
for (auto byte_index = 1u; byte_index < leading_ones; ++byte_index) {
|
||||
if (k + 3 >= string.length_in_code_units() || string.code_unit_at(k + 1) != '%')
|
||||
return vm.throw_completion<URIError>(ErrorType::URIMalformed);
|
||||
return decoded_builder.to_byte_string();
|
||||
utf8_bytes[byte_index] = TRY(decode_percent_encoded_byte(vm, string, k + 1));
|
||||
k += 3;
|
||||
}
|
||||
|
||||
auto utf8_view = Utf8View { StringView { reinterpret_cast<char const*>(utf8_bytes), leading_ones } };
|
||||
if (!utf8_view.validate(AllowLonelySurrogates::No))
|
||||
return vm.throw_completion<URIError>(ErrorType::URIMalformed);
|
||||
for (auto decoded_code_point : utf8_view)
|
||||
decoded_builder.append_code_point(decoded_code_point);
|
||||
}
|
||||
return decoded_builder.to_string();
|
||||
}
|
||||
|
||||
// 19.2.6.1 decodeURI ( encodedURI ), https://tc39.es/ecma262/#sec-decodeuri-encodeduri
|
||||
JS_DEFINE_NATIVE_FUNCTION(GlobalObject::decode_uri)
|
||||
{
|
||||
// 1. Let uriString be ? ToString(encodedURI).
|
||||
auto uri_string = TRY(vm.argument(0).to_byte_string(vm));
|
||||
auto uri_string = TRY(vm.argument(0).to_utf16_string(vm));
|
||||
|
||||
// 2. Let preserveEscapeSet be ";/?:@&=+$,#".
|
||||
// 3. Return ? Decode(uriString, preserveEscapeSet).
|
||||
auto decoded = TRY(decode(vm, uri_string, ";/?:@&=+$,#"sv));
|
||||
return PrimitiveString::create(vm, move(decoded));
|
||||
auto decoded = TRY(decode(vm, uri_string.utf16_view(), ";/?:@&=+$,#"sv));
|
||||
return PrimitiveString::create(vm, decoded);
|
||||
}
|
||||
|
||||
// 19.2.6.2 decodeURIComponent ( encodedURIComponent ), https://tc39.es/ecma262/#sec-decodeuricomponent-encodeduricomponent
|
||||
|
|
@ -500,12 +500,12 @@ JS_DEFINE_NATIVE_FUNCTION(GlobalObject::decode_uri_component)
|
|||
auto encoded_uri_component = vm.argument(0);
|
||||
|
||||
// 1. Let componentString be ? ToString(encodedURIComponent).
|
||||
auto uri_string = TRY(encoded_uri_component.to_byte_string(vm));
|
||||
auto uri_string = TRY(encoded_uri_component.to_utf16_string(vm));
|
||||
|
||||
// 2. Let preserveEscapeSet be the empty String.
|
||||
// 3. Return ? Decode(componentString, preserveEscapeSet).
|
||||
auto decoded = TRY(decode(vm, uri_string, ""sv));
|
||||
return PrimitiveString::create(vm, move(decoded));
|
||||
auto decoded = TRY(decode(vm, uri_string.utf16_view(), ""sv));
|
||||
return PrimitiveString::create(vm, decoded);
|
||||
}
|
||||
|
||||
// 19.2.6.3 encodeURI ( uri ), https://tc39.es/ecma262/#sec-encodeuri-uri
|
||||
|
|
@ -514,11 +514,11 @@ JS_DEFINE_NATIVE_FUNCTION(GlobalObject::encode_uri)
|
|||
auto uri = vm.argument(0);
|
||||
|
||||
// 1. Let uriString be ? ToString(uri).
|
||||
auto uri_string = TRY(uri.to_byte_string(vm));
|
||||
auto uri_string = TRY(uri.to_utf16_string(vm));
|
||||
|
||||
// 2. Let extraUnescaped be ";/?:@&=+$,#".
|
||||
// 3. Return ? Encode(uriString, extraUnescaped).
|
||||
auto encoded = TRY(encode(vm, uri_string, ";/?:@&=+$,abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.!~*'()#"sv));
|
||||
auto encoded = TRY(encode(vm, uri_string.utf16_view(), ";/?:@&=+$,abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.!~*'()#"sv));
|
||||
return PrimitiveString::create(vm, move(encoded));
|
||||
}
|
||||
|
||||
|
|
@ -528,11 +528,11 @@ JS_DEFINE_NATIVE_FUNCTION(GlobalObject::encode_uri_component)
|
|||
auto uri_component = vm.argument(0);
|
||||
|
||||
// 1. Let componentString be ? ToString(uriComponent).
|
||||
auto uri_string = TRY(uri_component.to_byte_string(vm));
|
||||
auto uri_string = TRY(uri_component.to_utf16_string(vm));
|
||||
|
||||
// 2. Let extraUnescaped be the empty String.
|
||||
// 3. Return ? Encode(componentString, extraUnescaped).
|
||||
auto encoded = TRY(encode(vm, uri_string, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.!~*'()"sv));
|
||||
auto encoded = TRY(encode(vm, uri_string.utf16_view(), "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.!~*'()"sv));
|
||||
return PrimitiveString::create(vm, move(encoded));
|
||||
}
|
||||
|
||||
|
|
@ -543,7 +543,7 @@ JS_DEFINE_NATIVE_FUNCTION(GlobalObject::escape)
|
|||
auto string = TRY(vm.argument(0).to_utf16_string(vm));
|
||||
|
||||
// 3. Let R be the empty String.
|
||||
StringBuilder escaped;
|
||||
StringBuilder escaped(StringBuilder::Mode::UTF16);
|
||||
|
||||
// 4. Let unescapedSet be the string-concatenation of the ASCII word characters and "@*+-./".
|
||||
auto unescaped_set = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@*_+-./"sv;
|
||||
|
|
@ -581,7 +581,7 @@ JS_DEFINE_NATIVE_FUNCTION(GlobalObject::escape)
|
|||
}
|
||||
|
||||
// 7. Return R.
|
||||
return PrimitiveString::create(vm, escaped.to_byte_string());
|
||||
return PrimitiveString::create(vm, escaped.to_utf16_string());
|
||||
}
|
||||
|
||||
// B.2.1.2 unescape ( string ), https://tc39.es/ecma262/#sec-unescape-string
|
||||
|
|
@ -598,7 +598,7 @@ JS_DEFINE_NATIVE_FUNCTION(GlobalObject::unescape)
|
|||
|
||||
// 4. Let k be 0.
|
||||
// 5. Repeat, while k ≠ length,
|
||||
for (auto k = 0; k < length; ++k) {
|
||||
for (size_t k = 0; k < length; ++k) {
|
||||
// a. Let c be the code unit at index k within string.
|
||||
u16 code_unit = string.code_unit_at(k);
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ static bool is_well_formed_language_tag_impl(ViewType locale)
|
|||
quick_sort(variants);
|
||||
|
||||
for (size_t i = 0; i < variants.size() - 1; ++i) {
|
||||
if (variants[i].equals_ignoring_case(variants[i + 1]))
|
||||
if (variants[i].equals_ignoring_ascii_case(variants[i + 1]))
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -121,12 +121,12 @@ bool is_well_formed_language_tag(Utf16View locale)
|
|||
}
|
||||
|
||||
// 6.2.2 CanonicalizeUnicodeLocaleId ( locale ), https://tc39.es/ecma402/#sec-canonicalizeunicodelocaleid
|
||||
String canonicalize_unicode_locale_id(StringView locale)
|
||||
Utf16String canonicalize_unicode_locale_id(StringView locale)
|
||||
{
|
||||
return Unicode::canonicalize_unicode_locale_id(locale);
|
||||
}
|
||||
|
||||
String canonicalize_unicode_locale_id(Utf16View locale)
|
||||
Utf16String canonicalize_unicode_locale_id(Utf16View locale)
|
||||
{
|
||||
return Unicode::canonicalize_unicode_locale_id(locale);
|
||||
}
|
||||
|
|
@ -189,8 +189,8 @@ Vector<TimeZoneIdentifier> const& available_named_time_zone_identifiers()
|
|||
auto primary = identifier;
|
||||
|
||||
// b. If identifier is a Link name and identifier is not "UTC", then
|
||||
if (identifier != "UTC"sv) {
|
||||
if (auto resolved = Unicode::resolve_primary_time_zone(identifier); resolved.has_value() && identifier != resolved) {
|
||||
if (identifier.utf16_view() != "UTC"sv) {
|
||||
if (auto resolved = Unicode::resolve_primary_time_zone(identifier.utf16_view().bytes()); resolved.has_value() && identifier != *resolved) {
|
||||
// i. Set primary to the Zone name that identifier resolves to, according to the rules for resolving Link
|
||||
// names in the IANA Time Zone Database.
|
||||
primary = resolved.release_value();
|
||||
|
|
@ -200,16 +200,19 @@ Vector<TimeZoneIdentifier> const& available_named_time_zone_identifiers()
|
|||
}
|
||||
|
||||
// c. If primary is one of "Etc/UTC", "Etc/GMT", or "GMT", set primary to "UTC".
|
||||
if (primary.is_one_of("Etc/UTC"sv, "Etc/GMT"sv, "GMT"sv))
|
||||
primary = "UTC"_string;
|
||||
if (primary.utf16_view().is_one_of("Etc/UTC"sv, "Etc/GMT"sv, "GMT"sv))
|
||||
primary = "UTC"_utf16;
|
||||
|
||||
// d. Let record be the Time Zone Identifier Record { [[Identifier]]: identifier, [[PrimaryIdentifier]]: primary }.
|
||||
TimeZoneIdentifier record { .identifier = identifier, .primary_identifier = primary };
|
||||
TimeZoneIdentifier record {
|
||||
.identifier = identifier,
|
||||
.primary_identifier = primary,
|
||||
};
|
||||
|
||||
// e. Append record to result.
|
||||
result.unchecked_append(move(record));
|
||||
|
||||
if (!found_utc && identifier == "UTC"sv && primary == "UTC"sv)
|
||||
if (!found_utc && identifier.utf16_view() == "UTC"sv && primary.utf16_view() == "UTC"sv)
|
||||
found_utc = true;
|
||||
}
|
||||
|
||||
|
|
@ -224,7 +227,7 @@ Vector<TimeZoneIdentifier> const& available_named_time_zone_identifiers()
|
|||
}
|
||||
|
||||
// 6.5.2 GetAvailableNamedTimeZoneIdentifier ( timeZoneIdentifier ), https://tc39.es/ecma402/#sec-getavailablenamedtimezoneidentifier
|
||||
Optional<TimeZoneIdentifier const&> get_available_named_time_zone_identifier(StringView time_zone_identifier)
|
||||
Optional<TimeZoneIdentifier const&> get_available_named_time_zone_identifier(Utf16View time_zone_identifier)
|
||||
{
|
||||
// 1. For each element record of AvailableNamedTimeZoneIdentifiers(), do
|
||||
for (auto const& record : available_named_time_zone_identifiers()) {
|
||||
|
|
@ -287,18 +290,18 @@ bool is_well_formed_unit_identifier(Utf16View unit_identifier)
|
|||
}
|
||||
|
||||
// 9.2.1 CanonicalizeLocaleList ( locales ), https://tc39.es/ecma402/#sec-canonicalizelocalelist
|
||||
ThrowCompletionOr<Vector<String>> canonicalize_locale_list(VM& vm, Value locales)
|
||||
ThrowCompletionOr<Vector<Utf16String>> canonicalize_locale_list(VM& vm, Value locales)
|
||||
{
|
||||
auto& realm = *vm.current_realm();
|
||||
|
||||
// 1. If locales is undefined, then
|
||||
if (locales.is_undefined()) {
|
||||
// a. Return a new empty List.
|
||||
return Vector<String> {};
|
||||
return Vector<Utf16String> {};
|
||||
}
|
||||
|
||||
// 2. Let seen be a new empty List.
|
||||
Vector<String> seen;
|
||||
Vector<Utf16String> seen;
|
||||
|
||||
Object* object = nullptr;
|
||||
// 3. If Type(locales) is String or Type(locales) is Object and locales has an [[InitializedLocale]] internal slot, then
|
||||
|
|
@ -334,12 +337,12 @@ ThrowCompletionOr<Vector<String>> canonicalize_locale_list(VM& vm, Value locales
|
|||
if (!key_value.is_string() && !key_value.is_object())
|
||||
return vm.throw_completion<TypeError>(ErrorType::NotAnObjectOrString, key_value);
|
||||
|
||||
String canonicalized_tag;
|
||||
Utf16String canonicalized_tag;
|
||||
|
||||
// iii. If Type(kValue) is Object and kValue has an [[InitializedLocale]] internal slot, then
|
||||
if (auto locale = key_value.as_if<Locale>()) {
|
||||
// 1. Let tag be kValue.[[Locale]].
|
||||
auto tag = locale->locale();
|
||||
auto tag = locale->locale().utf16_view();
|
||||
|
||||
// v. If IsWellFormedLanguageTag(tag) is false, throw a RangeError exception.
|
||||
if (!is_well_formed_language_tag(tag))
|
||||
|
|
@ -374,17 +377,15 @@ ThrowCompletionOr<Vector<String>> canonicalize_locale_list(VM& vm, Value locales
|
|||
}
|
||||
|
||||
// 9.2.3 LookupMatchingLocaleByPrefix ( availableLocales, requestedLocales ), https://tc39.es/ecma402/#sec-lookupmatchinglocalebyprefix
|
||||
Optional<MatchedLocale> lookup_matching_locale_by_prefix(ReadonlySpan<String> requested_locales)
|
||||
Optional<MatchedLocale> lookup_matching_locale_by_prefix(ReadonlySpan<Utf16String> requested_locales)
|
||||
{
|
||||
// 1. For each element locale of requestedLocales, do
|
||||
for (auto locale : requested_locales) {
|
||||
auto locale_id = Unicode::parse_unicode_locale_id(locale);
|
||||
auto locale_id = Unicode::parse_unicode_locale_id(locale.utf16_view());
|
||||
VERIFY(locale_id.has_value());
|
||||
|
||||
// a. Let extension be empty.
|
||||
Optional<Unicode::Extension> extension;
|
||||
String locale_without_extension;
|
||||
|
||||
// b. If locale contains a Unicode locale extension sequence, then
|
||||
if (auto extensions = locale_id->remove_extension_type<Unicode::LocaleExtension>(); !extensions.is_empty()) {
|
||||
VERIFY(extensions.size() == 1);
|
||||
|
|
@ -393,24 +394,24 @@ Optional<MatchedLocale> lookup_matching_locale_by_prefix(ReadonlySpan<String> re
|
|||
extension = extensions.take_first();
|
||||
|
||||
// ii. Set locale to the String value that is locale with any Unicode locale extension sequences removed.
|
||||
locale = locale_id->to_string();
|
||||
locale = locale_id->to_utf16_string();
|
||||
}
|
||||
|
||||
// c. Let prefix be locale.
|
||||
StringView prefix { locale };
|
||||
auto prefix = locale.utf16_view();
|
||||
|
||||
// d. Repeat, while prefix is not the empty String,
|
||||
while (!prefix.is_empty()) {
|
||||
// i. If availableLocales contains prefix, return the Record { [[locale]]: prefix, [[extension]]: extension }.
|
||||
if (Unicode::is_locale_available(prefix))
|
||||
return MatchedLocale { MUST(String::from_utf8(prefix)), move(extension) };
|
||||
if (Unicode::is_locale_available(prefix.bytes()))
|
||||
return MatchedLocale { Utf16String::from_utf16(prefix), move(extension) };
|
||||
|
||||
// ii. If prefix contains "-" (code unit 0x002D HYPHEN-MINUS), let pos be the index into prefix of the last
|
||||
// occurrence of "-"; else let pos be 0.
|
||||
auto position = prefix.find_last('-').value_or(0);
|
||||
auto position = prefix.find_last_code_point_offset('-').value_or(0);
|
||||
|
||||
// iii. Repeat, while pos ≥ 2 and the substring of prefix from pos - 2 to pos - 1 is "-",
|
||||
while (position >= 2 && prefix.substring_view(position - 2, 1) == '-') {
|
||||
while (position >= 2 && prefix.substring_view(position - 2, 1) == "-"sv) {
|
||||
// 1. Set pos to pos - 2.
|
||||
position -= 2;
|
||||
}
|
||||
|
|
@ -425,7 +426,7 @@ Optional<MatchedLocale> lookup_matching_locale_by_prefix(ReadonlySpan<String> re
|
|||
}
|
||||
|
||||
// 9.2.4 LookupMatchingLocaleByBestFit ( availableLocales, requestedLocales ), https://tc39.es/ecma402/#sec-lookupmatchinglocalebybestfit
|
||||
Optional<MatchedLocale> lookup_matching_locale_by_best_fit(ReadonlySpan<String> requested_locales)
|
||||
Optional<MatchedLocale> lookup_matching_locale_by_best_fit(ReadonlySpan<Utf16String> requested_locales)
|
||||
{
|
||||
// The algorithm is implementation dependent, but should produce results that a typical user of the requested locales
|
||||
// would consider at least as good as those produced by the LookupMatchingLocaleByPrefix algorithm.
|
||||
|
|
@ -433,7 +434,7 @@ Optional<MatchedLocale> lookup_matching_locale_by_best_fit(ReadonlySpan<String>
|
|||
}
|
||||
|
||||
// 9.2.6 InsertUnicodeExtensionAndCanonicalize ( locale, attributes, keywords ), https://tc39.es/ecma402/#sec-insert-unicode-extension-and-canonicalize
|
||||
String insert_unicode_extension_and_canonicalize(Unicode::LocaleID locale, Vector<String> attributes, Vector<Unicode::Keyword> keywords)
|
||||
Utf16String insert_unicode_extension_and_canonicalize(Unicode::LocaleID locale, Vector<Utf16String> attributes, Vector<Unicode::Keyword> keywords)
|
||||
{
|
||||
// Note: This implementation differs from the spec in how the extension is inserted. The spec assumes
|
||||
// the input to this method is a string, and is written such that operations are performed on parts
|
||||
|
|
@ -442,11 +443,11 @@ String insert_unicode_extension_and_canonicalize(Unicode::LocaleID locale, Vecto
|
|||
locale.extensions.append(Unicode::LocaleExtension { move(attributes), move(keywords) });
|
||||
|
||||
// 10. Return CanonicalizeUnicodeLocaleId(newLocale).
|
||||
return JS::Intl::canonicalize_unicode_locale_id(locale.to_string());
|
||||
return JS::Intl::canonicalize_unicode_locale_id(locale.to_utf16_string());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static auto& find_key_in_value(T& value, StringView key)
|
||||
static auto& find_key_in_value(T& value, Utf16View key)
|
||||
{
|
||||
if (key == "ca"sv)
|
||||
return value.ca;
|
||||
|
|
@ -465,7 +466,7 @@ static auto& find_key_in_value(T& value, StringView key)
|
|||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
static Vector<LocaleKey> available_keyword_values(StringView locale, StringView key)
|
||||
static Vector<LocaleKey> available_keyword_values(Utf16View locale, Utf16View key)
|
||||
{
|
||||
auto key_locale_data = Unicode::available_keyword_values(locale, key);
|
||||
|
||||
|
|
@ -485,9 +486,9 @@ static Vector<LocaleKey> available_keyword_values(StringView locale, StringView
|
|||
}
|
||||
|
||||
// 9.2.7 ResolveLocale ( availableLocales, requestedLocales, options, relevantExtensionKeys, localeData ), https://tc39.es/ecma402/#sec-resolvelocale
|
||||
ResolvedLocale resolve_locale(ReadonlySpan<String> requested_locales, LocaleOptions const& options, ReadonlySpan<StringView> relevant_extension_keys)
|
||||
ResolvedLocale resolve_locale(ReadonlySpan<Utf16String> requested_locales, LocaleOptions const& options, ReadonlySpan<Utf16View> relevant_extension_keys)
|
||||
{
|
||||
static auto true_string = "true"_string;
|
||||
auto true_string = "true"_utf16;
|
||||
|
||||
// 1. Let matcher be options.[[localeMatcher]].
|
||||
auto const& matcher = options.locale_matcher;
|
||||
|
|
@ -507,7 +508,7 @@ ResolvedLocale resolve_locale(ReadonlySpan<String> requested_locales, LocaleOpti
|
|||
|
||||
// 4. If r is undefined, set r to the Record { [[locale]]: DefaultLocale(), [[extension]]: empty }.
|
||||
if (!matcher_result.has_value())
|
||||
matcher_result = MatchedLocale { MUST(String::from_utf8(Unicode::default_locale())), {} };
|
||||
matcher_result = MatchedLocale { Utf16String::from_utf16(Unicode::default_locale()), {} };
|
||||
|
||||
// 5. Let foundLocale be r.[[locale]].
|
||||
auto found_locale = move(matcher_result->locale);
|
||||
|
|
@ -541,7 +542,7 @@ ResolvedLocale resolve_locale(ReadonlySpan<String> requested_locales, LocaleOpti
|
|||
for (auto const& key : relevant_extension_keys) {
|
||||
// a. Let keyLocaleData be foundLocaleData.[[<key>]].
|
||||
// b. Assert: keyLocaleData is a List.
|
||||
auto key_locale_data = available_keyword_values(found_locale, key);
|
||||
auto key_locale_data = available_keyword_values(found_locale.utf16_view(), key);
|
||||
|
||||
// c. Let value be keyLocaleData[0].
|
||||
// d. Assert: value is a String or value is null.
|
||||
|
|
@ -551,7 +552,7 @@ ResolvedLocale resolve_locale(ReadonlySpan<String> requested_locales, LocaleOpti
|
|||
Optional<Unicode::Keyword> supported_keyword;
|
||||
|
||||
// f. If keywords contains an element whose [[Key]] is key, then
|
||||
if (auto entry = keywords.find_if([&](auto const& entry) { return entry.key == key; }); entry != keywords.end()) {
|
||||
if (auto entry = keywords.find_if([&](auto const& entry) { return entry.key.utf16_view() == key; }); entry != keywords.end()) {
|
||||
// i. Let entry be the element of keywords whose [[Key]] is key.
|
||||
// ii. Let requestedValue be entry.[[Value]].
|
||||
auto requested_value = entry->value;
|
||||
|
|
@ -564,7 +565,7 @@ ResolvedLocale resolve_locale(ReadonlySpan<String> requested_locales, LocaleOpti
|
|||
value = move(requested_value);
|
||||
|
||||
// b. Set supportedKeyword to the Record { [[Key]]: key, [[Value]]: value }.
|
||||
supported_keyword = Unicode::Keyword { MUST(String::from_utf8(key)), move(entry->value) };
|
||||
supported_keyword = Unicode::Keyword { Utf16String::from_utf16(key), move(entry->value) };
|
||||
}
|
||||
}
|
||||
// iv. Else if keyLocaleData contains "true", then
|
||||
|
|
@ -573,7 +574,7 @@ ResolvedLocale resolve_locale(ReadonlySpan<String> requested_locales, LocaleOpti
|
|||
value = true_string;
|
||||
|
||||
// 2. Set supportedKeyword to the Record { [[Key]]: key, [[Value]]: "" }.
|
||||
supported_keyword = Unicode::Keyword { MUST(String::from_utf8(key)), {} };
|
||||
supported_keyword = Unicode::Keyword { Utf16String::from_utf16(key), {} };
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -583,13 +584,14 @@ ResolvedLocale resolve_locale(ReadonlySpan<String> requested_locales, LocaleOpti
|
|||
auto options_value = find_key_in_value(options, key);
|
||||
|
||||
// j. If optionsValue is a String, then
|
||||
if (auto* options_string = options_value.has_value() ? options_value->get_pointer<String>() : nullptr) {
|
||||
if (auto* options_string = options_value.has_value() ? options_value->get_pointer<Utf16String>() : nullptr) {
|
||||
// i. Let ukey be the ASCII-lowercase of key.
|
||||
// NOTE: `key` is always lowercase, and this step is likely to be removed:
|
||||
// https://github.com/tc39/ecma402/pull/846#discussion_r1428263375
|
||||
|
||||
// ii. Set optionsValue to CanonicalizeUValue(ukey, optionsValue).
|
||||
*options_string = Unicode::canonicalize_unicode_extension_values(key, *options_string);
|
||||
auto canonicalized = Unicode::canonicalize_unicode_extension_values(key.bytes(), options_string->utf16_view());
|
||||
*options_string = move(canonicalized);
|
||||
|
||||
// iii. If optionsValue is the empty String, then
|
||||
if (options_string->is_empty()) {
|
||||
|
|
@ -611,31 +613,36 @@ ResolvedLocale resolve_locale(ReadonlySpan<String> requested_locales, LocaleOpti
|
|||
if (supported_keyword.has_value())
|
||||
supported_keywords.append(supported_keyword.release_value());
|
||||
|
||||
if (auto* value_string = value.get_pointer<String>())
|
||||
icu_keywords.empend(MUST(String::from_utf8(key)), *value_string);
|
||||
if (auto* value_string = value.get_pointer<Utf16String>())
|
||||
icu_keywords.empend(Utf16String::from_utf16(key), *value_string);
|
||||
|
||||
// m. Set result.[[<key>]] to value.
|
||||
find_key_in_value(result, key) = move(value);
|
||||
if (auto* value_string = value.get_pointer<Utf16String>())
|
||||
find_key_in_value(result, key) = *value_string;
|
||||
else
|
||||
find_key_in_value(result, key) = Empty {};
|
||||
}
|
||||
|
||||
// AD-HOC: For ICU, we need to form a locale with all relevant extension keys present.
|
||||
if (icu_keywords.is_empty()) {
|
||||
result.icu_locale = found_locale;
|
||||
} else {
|
||||
auto locale_id = Unicode::parse_unicode_locale_id(found_locale);
|
||||
auto locale_id = Unicode::parse_unicode_locale_id(found_locale.utf16_view());
|
||||
VERIFY(locale_id.has_value());
|
||||
|
||||
result.icu_locale = insert_unicode_extension_and_canonicalize(locale_id.release_value(), {}, move(icu_keywords));
|
||||
auto icu_locale = insert_unicode_extension_and_canonicalize(locale_id.release_value(), {}, move(icu_keywords));
|
||||
result.icu_locale = move(icu_locale);
|
||||
}
|
||||
|
||||
// 14. If supportedKeywords is not empty, then
|
||||
if (!supported_keywords.is_empty()) {
|
||||
auto locale_id = Unicode::parse_unicode_locale_id(found_locale);
|
||||
auto locale_id = Unicode::parse_unicode_locale_id(found_locale.utf16_view());
|
||||
VERIFY(locale_id.has_value());
|
||||
|
||||
// a. Let supportedAttributes be a new empty List.
|
||||
// b. Set foundLocale to InsertUnicodeExtensionAndCanonicalize(foundLocale, supportedAttributes, supportedKeywords).
|
||||
found_locale = insert_unicode_extension_and_canonicalize(locale_id.release_value(), {}, move(supported_keywords));
|
||||
auto supported_locale = insert_unicode_extension_and_canonicalize(locale_id.release_value(), {}, move(supported_keywords));
|
||||
found_locale = move(supported_locale);
|
||||
}
|
||||
|
||||
// 15. Set result.[[Locale]] to foundLocale.
|
||||
|
|
@ -662,7 +669,7 @@ ThrowCompletionOr<ResolvedOptions> resolve_options(VM& vm, IntlObject& object, V
|
|||
: TRY(get_options_object(vm, options_value));
|
||||
|
||||
// 4. Let matcher be ? GetOption(options, "localeMatcher", STRING, « "lookup", "best fit" », "best fit").
|
||||
auto matcher = TRY(get_option(vm, options, vm.names.localeMatcher, OptionType::String, { "lookup"sv, "best fit"sv }, "best fit"sv));
|
||||
auto matcher = TRY(get_option(vm, options, vm.names.localeMatcher, OptionType::String, { "lookup"sv, "best fit"sv }, u"best fit"sv));
|
||||
|
||||
// 5. Let opt be the Record { [[localeMatcher]]: matcher }.
|
||||
LocaleOptions opt {};
|
||||
|
|
@ -687,10 +694,10 @@ ThrowCompletionOr<ResolvedOptions> resolve_options(VM& vm, IntlObject& object, V
|
|||
auto value_string_view = value_string.utf16_view();
|
||||
|
||||
// ii. If value cannot be matched by the type Unicode locale nonterminal, throw a RangeError exception.
|
||||
if (!value_string_view.is_ascii() || !Unicode::is_type_identifier(value_string_view))
|
||||
if (!value_string_view.has_ascii_storage() || !Unicode::is_type_identifier(value_string_view))
|
||||
return vm.throw_completion<RangeError>(ErrorType::OptionIsNotValidValue, value_string_view, descriptor.property);
|
||||
|
||||
locale_key = MUST(value_string_view.to_utf8());
|
||||
locale_key = move(value_string);
|
||||
}
|
||||
|
||||
// e. Let key be desc.[[Key]].
|
||||
|
|
@ -715,7 +722,7 @@ ThrowCompletionOr<ResolvedOptions> resolve_options(VM& vm, IntlObject& object, V
|
|||
}
|
||||
|
||||
// 9.2.9 FilterLocales ( availableLocales, requestedLocales, options ), https://tc39.es/ecma402/#sec-lookupsupportedlocales
|
||||
ThrowCompletionOr<GC::Ref<Array>> filter_locales(VM& vm, ReadonlySpan<String> requested_locales, Value options_value)
|
||||
ThrowCompletionOr<GC::Ref<Array>> filter_locales(VM& vm, ReadonlySpan<Utf16String> requested_locales, Value options_value)
|
||||
{
|
||||
auto& realm = *vm.current_realm();
|
||||
|
||||
|
|
@ -723,10 +730,10 @@ ThrowCompletionOr<GC::Ref<Array>> filter_locales(VM& vm, ReadonlySpan<String> re
|
|||
auto options = TRY(coerce_options_to_object(vm, options_value));
|
||||
|
||||
// 2. Let matcher be ? GetOption(options, "localeMatcher", string, « "lookup", "best fit" », "best fit").
|
||||
auto matcher = TRY(get_option(vm, options, vm.names.localeMatcher, OptionType::String, { "lookup"sv, "best fit"sv }, "best fit"sv));
|
||||
auto matcher = TRY(get_option(vm, options, vm.names.localeMatcher, OptionType::String, { "lookup"sv, "best fit"sv }, u"best fit"sv));
|
||||
|
||||
// 3. Let subset be a new empty List.
|
||||
Vector<String> subset;
|
||||
Vector<Utf16String> subset;
|
||||
|
||||
// 4. For each element locale of requestedLocales, do
|
||||
for (auto const& locale : requested_locales) {
|
||||
|
|
@ -749,7 +756,7 @@ ThrowCompletionOr<GC::Ref<Array>> filter_locales(VM& vm, ReadonlySpan<String> re
|
|||
}
|
||||
|
||||
// 5. Return CreateArrayFromList(subset).
|
||||
return Array::create_from<String>(realm, subset, [&vm](auto& locale) { return PrimitiveString::create(vm, move(locale)); });
|
||||
return Array::create_from<Utf16String>(realm, subset, [&vm](auto const& locale) { return PrimitiveString::create(vm, locale); });
|
||||
}
|
||||
|
||||
// 9.2.11 CoerceOptionsToObject ( options ), https://tc39.es/ecma402/#sec-coerceoptionstoobject
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <AK/EnumBits.h>
|
||||
#include <AK/Span.h>
|
||||
#include <AK/String.h>
|
||||
#include <AK/Utf16String.h>
|
||||
#include <AK/Utf16View.h>
|
||||
#include <AK/Variant.h>
|
||||
#include <AK/Vector.h>
|
||||
|
|
@ -20,7 +21,8 @@
|
|||
|
||||
namespace JS::Intl {
|
||||
|
||||
using LocaleKey = Variant<Empty, String>;
|
||||
using LocaleKey = Variant<Empty, Utf16String>;
|
||||
using ResolvedLocaleKey = Variant<Empty, Utf16String>;
|
||||
|
||||
struct LocaleOptions {
|
||||
Value locale_matcher;
|
||||
|
|
@ -34,19 +36,19 @@ struct LocaleOptions {
|
|||
};
|
||||
|
||||
struct MatchedLocale {
|
||||
String locale;
|
||||
Utf16String locale;
|
||||
Optional<Unicode::Extension> extension;
|
||||
};
|
||||
|
||||
struct ResolvedLocale {
|
||||
String locale;
|
||||
String icu_locale;
|
||||
LocaleKey ca; // [[Calendar]]
|
||||
LocaleKey co; // [[Collation]]
|
||||
LocaleKey hc; // [[HourCycle]]
|
||||
LocaleKey kf; // [[CaseFirst]]
|
||||
LocaleKey kn; // [[Numeric]]
|
||||
LocaleKey nu; // [[NumberingSystem]]
|
||||
Utf16String locale;
|
||||
Utf16String icu_locale;
|
||||
ResolvedLocaleKey ca; // [[Calendar]]
|
||||
ResolvedLocaleKey co; // [[Collation]]
|
||||
ResolvedLocaleKey hc; // [[HourCycle]]
|
||||
ResolvedLocaleKey kf; // [[CaseFirst]]
|
||||
ResolvedLocaleKey kn; // [[Numeric]]
|
||||
ResolvedLocaleKey nu; // [[NumberingSystem]]
|
||||
};
|
||||
|
||||
struct ResolvedOptions {
|
||||
|
|
@ -66,20 +68,20 @@ using StringOrBoolean = Variant<StringView, bool>;
|
|||
|
||||
bool is_well_formed_language_tag(StringView locale);
|
||||
bool is_well_formed_language_tag(Utf16View locale);
|
||||
String canonicalize_unicode_locale_id(StringView locale);
|
||||
String canonicalize_unicode_locale_id(Utf16View locale);
|
||||
Utf16String canonicalize_unicode_locale_id(StringView locale);
|
||||
Utf16String canonicalize_unicode_locale_id(Utf16View locale);
|
||||
bool is_well_formed_currency_code(StringView currency);
|
||||
bool is_well_formed_currency_code(Utf16View currency);
|
||||
Vector<TimeZoneIdentifier> const& available_named_time_zone_identifiers();
|
||||
Optional<TimeZoneIdentifier const&> get_available_named_time_zone_identifier(StringView time_zone_identifier);
|
||||
Optional<TimeZoneIdentifier const&> get_available_named_time_zone_identifier(Utf16View time_zone_identifier);
|
||||
bool is_well_formed_unit_identifier(Utf16View unit_identifier);
|
||||
ThrowCompletionOr<Vector<String>> canonicalize_locale_list(VM&, Value locales);
|
||||
Optional<MatchedLocale> lookup_matching_locale_by_prefix(ReadonlySpan<String> requested_locales);
|
||||
Optional<MatchedLocale> lookup_matching_locale_by_best_fit(ReadonlySpan<String> requested_locales);
|
||||
String insert_unicode_extension_and_canonicalize(Unicode::LocaleID locale_id, Vector<String> attributes, Vector<Unicode::Keyword> keywords);
|
||||
ResolvedLocale resolve_locale(ReadonlySpan<String> requested_locales, LocaleOptions const& options, ReadonlySpan<StringView> relevant_extension_keys);
|
||||
ThrowCompletionOr<Vector<Utf16String>> canonicalize_locale_list(VM&, Value locales);
|
||||
Optional<MatchedLocale> lookup_matching_locale_by_prefix(ReadonlySpan<Utf16String> requested_locales);
|
||||
Optional<MatchedLocale> lookup_matching_locale_by_best_fit(ReadonlySpan<Utf16String> requested_locales);
|
||||
Utf16String insert_unicode_extension_and_canonicalize(Unicode::LocaleID locale_id, Vector<Utf16String> attributes, Vector<Unicode::Keyword> keywords);
|
||||
ResolvedLocale resolve_locale(ReadonlySpan<Utf16String> requested_locales, LocaleOptions const& options, ReadonlySpan<Utf16View> relevant_extension_keys);
|
||||
ThrowCompletionOr<ResolvedOptions> resolve_options(VM& vm, IntlObject& object, Value locales, Value options_value, SpecialBehaviors special_behaviours = SpecialBehaviors::None, Function<void(LocaleOptions&)> modify_resolution_options = {});
|
||||
ThrowCompletionOr<GC::Ref<Array>> filter_locales(VM& vm, ReadonlySpan<String> requested_locales, Value options);
|
||||
ThrowCompletionOr<GC::Ref<Array>> filter_locales(VM& vm, ReadonlySpan<Utf16String> requested_locales, Value options);
|
||||
ThrowCompletionOr<GC::Ref<Object>> coerce_options_to_object(VM&, Value options);
|
||||
ThrowCompletionOr<StringOrBoolean> get_boolean_or_string_number_format_option(VM& vm, Object const& options, PropertyKey const& property, ReadonlySpan<StringView> string_values, StringOrBoolean fallback);
|
||||
ThrowCompletionOr<Optional<int>> default_number_option(VM&, Value value, int minimum, int maximum, Optional<int> fallback);
|
||||
|
|
|
|||
|
|
@ -24,10 +24,10 @@ void Collator::visit_edges(Visitor& visitor)
|
|||
}
|
||||
|
||||
// 10.2.3 Internal slots, https://tc39.es/ecma402/#sec-intl-collator-internal-slots
|
||||
ReadonlySpan<StringView> Collator::relevant_extension_keys() const
|
||||
ReadonlySpan<Utf16View> Collator::relevant_extension_keys() const
|
||||
{
|
||||
// The value of the [[RelevantExtensionKeys]] internal slot is a List that must include the element "co", may include any or all of the elements "kf" and "kn", and must not include any other elements.
|
||||
static constexpr AK::Array keys { "co"sv, "kf"sv, "kn"sv };
|
||||
static constexpr AK::Array<Utf16View, 3> keys { "co"sv, "kf"sv, "kn"sv };
|
||||
return keys;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <AK/String.h>
|
||||
#include <AK/StringView.h>
|
||||
#include <AK/Utf16String.h>
|
||||
#include <AK/Utf16View.h>
|
||||
#include <LibJS/Runtime/Intl/CollatorCompareFunction.h>
|
||||
#include <LibJS/Runtime/Intl/IntlObject.h>
|
||||
|
|
@ -22,26 +23,26 @@ class Collator final : public IntlObject {
|
|||
public:
|
||||
virtual ~Collator() override = default;
|
||||
|
||||
virtual ReadonlySpan<StringView> relevant_extension_keys() const override;
|
||||
virtual ReadonlySpan<Utf16View> relevant_extension_keys() const override;
|
||||
virtual ReadonlySpan<ResolutionOptionDescriptor> resolution_option_descriptors(VM&) const override;
|
||||
|
||||
String const& locale() const { return m_locale; }
|
||||
void set_locale(String locale) { m_locale = move(locale); }
|
||||
Utf16String const& locale() const { return m_locale; }
|
||||
void set_locale(Utf16String locale) { m_locale = move(locale); }
|
||||
|
||||
Unicode::Usage usage() const { return m_usage; }
|
||||
void set_usage(Utf16View usage) { m_usage = Unicode::usage_from_string(usage); }
|
||||
StringView usage_string() const LIFETIME_BOUND { return Unicode::usage_to_string(m_usage); }
|
||||
Utf16String usage_string() const { return Unicode::usage_to_string(m_usage); }
|
||||
|
||||
Unicode::Sensitivity sensitivity() const { return m_sensitivity; }
|
||||
void set_sensitivity(Unicode::Sensitivity sensitivity) { m_sensitivity = sensitivity; }
|
||||
StringView sensitivity_string() const LIFETIME_BOUND { return Unicode::sensitivity_to_string(m_sensitivity); }
|
||||
Utf16String sensitivity_string() const { return Unicode::sensitivity_to_string(m_sensitivity); }
|
||||
|
||||
Unicode::CaseFirst case_first() const { return m_case_first; }
|
||||
void set_case_first(StringView case_first) { m_case_first = Unicode::case_first_from_string(case_first); }
|
||||
StringView case_first_string() const LIFETIME_BOUND { return Unicode::case_first_to_string(m_case_first); }
|
||||
void set_case_first(Utf16View case_first) { m_case_first = Unicode::case_first_from_string(case_first); }
|
||||
Utf16String case_first_string() const { return Unicode::case_first_to_string(m_case_first); }
|
||||
|
||||
String const& collation() const { return m_collation; }
|
||||
void set_collation(String collation) { m_collation = move(collation); }
|
||||
Utf16String const& collation() const { return m_collation; }
|
||||
void set_collation(Utf16String collation) { m_collation = move(collation); }
|
||||
|
||||
bool ignore_punctuation() const { return m_ignore_punctuation; }
|
||||
void set_ignore_punctuation(bool ignore_punctuation) { m_ignore_punctuation = ignore_punctuation; }
|
||||
|
|
@ -60,11 +61,11 @@ private:
|
|||
|
||||
virtual void visit_edges(Visitor&) override;
|
||||
|
||||
String m_locale; // [[Locale]]
|
||||
Utf16String m_locale; // [[Locale]]
|
||||
Unicode::Usage m_usage { Unicode::Usage::Sort }; // [[Usage]]
|
||||
Unicode::Sensitivity m_sensitivity { Unicode::Sensitivity::Variant }; // [[Sensitivity]]
|
||||
Unicode::CaseFirst m_case_first { Unicode::CaseFirst::False }; // [[CaseFirst]]
|
||||
String m_collation; // [[Collation]]
|
||||
Utf16String m_collation; // [[Collation]]
|
||||
bool m_ignore_punctuation { false }; // [[IgnorePunctuation]]
|
||||
bool m_numeric { false }; // [[Numeric]]
|
||||
GC::Ptr<CollatorCompareFunction> m_bound_compare; // [[BoundCompare]]
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ void CollatorCompareFunction::initialize(Realm& realm)
|
|||
Base::initialize(realm);
|
||||
auto& vm = this->vm();
|
||||
define_direct_property(vm.names.length, Value(2), Attribute::Configurable);
|
||||
define_direct_property(vm.names.name, PrimitiveString::create(vm, String {}), Attribute::Configurable);
|
||||
define_direct_property(vm.names.name, PrimitiveString::create(vm, Utf16String {}), Attribute::Configurable);
|
||||
}
|
||||
|
||||
void CollatorCompareFunction::visit_edges(Visitor& visitor)
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ ThrowCompletionOr<GC::Ref<Object>> CollatorConstructor::construct(FunctionObject
|
|||
auto options = TRY(coerce_options_to_object(vm, options_value));
|
||||
|
||||
// 7. Let usage be ? GetOption(options, "usage", string, « "sort", "search" », "sort").
|
||||
auto usage = TRY(get_option(vm, options, vm.names.usage, OptionType::String, { "sort"sv, "search"sv }, "sort"sv));
|
||||
auto usage = TRY(get_option(vm, options, vm.names.usage, OptionType::String, { "sort"sv, "search"sv }, u"sort"sv));
|
||||
|
||||
// 8. Set collator.[[Usage]] to usage.
|
||||
collator->set_usage(usage.as_string().utf16_string_view());
|
||||
|
|
@ -77,7 +77,7 @@ ThrowCompletionOr<GC::Ref<Object>> CollatorConstructor::construct(FunctionObject
|
|||
// a. Let localeData be %Intl.Collator%.[[SearchLocaleData]].
|
||||
|
||||
// 11. Let optionsResolution be ? ResolveOptions(%Intl.Collator%, localeData, CreateArrayFromList(requestedLocales), options).
|
||||
auto requested_locales_array = Array::create_from<String>(realm, requested_locales, [&](auto& locale) { return PrimitiveString::create(vm, move(locale)); });
|
||||
auto requested_locales_array = Array::create_from<Utf16String>(realm, requested_locales, [&](auto const& locale) { return PrimitiveString::create(vm, locale); });
|
||||
auto options_resolution = TRY(resolve_options(vm, collator, requested_locales_array, options_value));
|
||||
|
||||
// 12. Let r be optionsResolution.[[ResolvedLocale]].
|
||||
|
|
@ -88,25 +88,25 @@ ThrowCompletionOr<GC::Ref<Object>> CollatorConstructor::construct(FunctionObject
|
|||
|
||||
// 14. If r.[[co]] is null, let collation be "default". Otherwise, let collation be r.[[co]].
|
||||
auto collation = result.co.has<Empty>()
|
||||
? "default"_string
|
||||
: move(result.co.get<String>());
|
||||
? "default"_utf16
|
||||
: move(result.co.get<Utf16String>());
|
||||
|
||||
// 15. Set collator.[[Collation]] to collation.
|
||||
collator->set_collation(move(collation));
|
||||
|
||||
// 16. Set collator.[[Numeric]] to SameValue(r.[[kn]], "true").
|
||||
collator->set_numeric(result.kn == "true"_string);
|
||||
collator->set_numeric(result.kn.has<Utf16String>() && result.kn.get<Utf16String>().utf16_view() == "true"sv);
|
||||
|
||||
// 17. Set collator.[[CaseFirst]] to r.[[kf]].
|
||||
if (auto const* resolved_case_first = result.kf.get_pointer<String>())
|
||||
collator->set_case_first(*resolved_case_first);
|
||||
if (auto const* resolved_case_first = result.kf.get_pointer<Utf16String>())
|
||||
collator->set_case_first(resolved_case_first->utf16_view());
|
||||
|
||||
// 18. Let resolvedLocaleData be r.[[LocaleData]].
|
||||
|
||||
// 19. If usage is "sort", let defaultSensitivity be "variant". Otherwise, let defaultSensitivity be resolvedLocaleData.[[sensitivity]].
|
||||
// NOTE: We do not acquire resolvedLocaleData.[[sensitivity]] here. Instead, we let LibUnicode fill in the
|
||||
// default value if an override was not provided here.
|
||||
auto default_sensitivity = collator->usage() == Unicode::Usage::Sort ? "variant"sv : OptionDefault {};
|
||||
auto default_sensitivity = collator->usage() == Unicode::Usage::Sort ? OptionDefault { u"variant"sv } : OptionDefault {};
|
||||
|
||||
// 20. Set collator.[[Sensitivity]] to ? GetOption(options, "sensitivity", string, « "base", "accent", "case", "variant" », defaultSensitivity).
|
||||
auto sensitivity_value = TRY(get_option(vm, options, vm.names.sensitivity, OptionType::String, { "base"sv, "accent"sv, "case"sv, "variant"sv }, default_sensitivity));
|
||||
|
|
@ -128,9 +128,9 @@ ThrowCompletionOr<GC::Ref<Object>> CollatorConstructor::construct(FunctionObject
|
|||
|
||||
// Non-standard, create an ICU collator for this Intl object.
|
||||
auto icu_collator = Unicode::Collator::create(
|
||||
collator->locale(),
|
||||
result.icu_locale.utf16_view().bytes(),
|
||||
collator->usage(),
|
||||
collator->collation(),
|
||||
collator->collation().utf16_view().bytes(),
|
||||
sensitivity,
|
||||
collator->case_first(),
|
||||
collator->numeric(),
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ void CollatorPrototype::initialize(Realm& realm)
|
|||
auto& vm = this->vm();
|
||||
|
||||
// 10.3.4 Intl.Collator.prototype [ %Symbol.toStringTag% ], https://tc39.es/ecma402/#sec-intl.collator.prototype-%symbol.tostringtag%
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Intl.Collator"_string), Attribute::Configurable);
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Intl.Collator"_utf16_fly_string), Attribute::Configurable);
|
||||
|
||||
u8 attr = Attribute::Writable | Attribute::Configurable;
|
||||
define_native_function(realm, vm.names.resolvedOptions, resolved_options, 0, attr);
|
||||
|
|
|
|||
|
|
@ -36,10 +36,10 @@ void DateTimeFormat::visit_edges(Cell::Visitor& visitor)
|
|||
}
|
||||
|
||||
// 11.2.3 Internal slots, https://tc39.es/ecma402/#sec-intl.datetimeformat-internal-slots
|
||||
ReadonlySpan<StringView> DateTimeFormat::relevant_extension_keys() const
|
||||
ReadonlySpan<Utf16View> DateTimeFormat::relevant_extension_keys() const
|
||||
{
|
||||
// The value of the [[RelevantExtensionKeys]] internal slot is « "ca", "hc", "nu" ».
|
||||
static constexpr AK::Array keys { "ca"sv, "hc"sv, "nu"sv };
|
||||
static constexpr AK::Array<Utf16View, 3> keys { "ca"sv, "hc"sv, "nu"sv };
|
||||
return keys;
|
||||
}
|
||||
|
||||
|
|
@ -75,32 +75,32 @@ static Optional<Unicode::DateTimeFormat const&> get_or_create_formatter(StringVi
|
|||
|
||||
Optional<Unicode::DateTimeFormat const&> DateTimeFormat::temporal_plain_date_formatter()
|
||||
{
|
||||
return get_or_create_formatter(m_icu_locale, "GMT+00:00"sv, m_temporal_plain_date_formatter, m_temporal_plain_date_format);
|
||||
return get_or_create_formatter(m_icu_locale.utf16_view().bytes(), "GMT+00:00"sv, m_temporal_plain_date_formatter, m_temporal_plain_date_format);
|
||||
}
|
||||
|
||||
Optional<Unicode::DateTimeFormat const&> DateTimeFormat::temporal_plain_year_month_formatter()
|
||||
{
|
||||
return get_or_create_formatter(m_icu_locale, "GMT+00:00"sv, m_temporal_plain_year_month_formatter, m_temporal_plain_year_month_format);
|
||||
return get_or_create_formatter(m_icu_locale.utf16_view().bytes(), "GMT+00:00"sv, m_temporal_plain_year_month_formatter, m_temporal_plain_year_month_format);
|
||||
}
|
||||
|
||||
Optional<Unicode::DateTimeFormat const&> DateTimeFormat::temporal_plain_month_day_formatter()
|
||||
{
|
||||
return get_or_create_formatter(m_icu_locale, "GMT+00:00"sv, m_temporal_plain_month_day_formatter, m_temporal_plain_month_day_format);
|
||||
return get_or_create_formatter(m_icu_locale.utf16_view().bytes(), "GMT+00:00"sv, m_temporal_plain_month_day_formatter, m_temporal_plain_month_day_format);
|
||||
}
|
||||
|
||||
Optional<Unicode::DateTimeFormat const&> DateTimeFormat::temporal_plain_time_formatter()
|
||||
{
|
||||
return get_or_create_formatter(m_icu_locale, "GMT+00:00"sv, m_temporal_plain_time_formatter, m_temporal_plain_time_format);
|
||||
return get_or_create_formatter(m_icu_locale.utf16_view().bytes(), "GMT+00:00"sv, m_temporal_plain_time_formatter, m_temporal_plain_time_format);
|
||||
}
|
||||
|
||||
Optional<Unicode::DateTimeFormat const&> DateTimeFormat::temporal_plain_date_time_formatter()
|
||||
{
|
||||
return get_or_create_formatter(m_icu_locale, "GMT+00:00"sv, m_temporal_plain_date_time_formatter, m_temporal_plain_date_time_format);
|
||||
return get_or_create_formatter(m_icu_locale.utf16_view().bytes(), "GMT+00:00"sv, m_temporal_plain_date_time_formatter, m_temporal_plain_date_time_format);
|
||||
}
|
||||
|
||||
Optional<Unicode::DateTimeFormat const&> DateTimeFormat::temporal_instant_formatter()
|
||||
{
|
||||
return get_or_create_formatter(m_icu_locale, m_temporal_time_zone, m_temporal_instant_formatter, m_temporal_instant_format);
|
||||
return get_or_create_formatter(m_icu_locale.utf16_view().bytes(), m_temporal_time_zone.utf16_view().bytes(), m_temporal_instant_formatter, m_temporal_instant_format);
|
||||
}
|
||||
|
||||
// 11.5.5 FormatDateTimePattern ( dateTimeFormat, patternParts, x, rangeFormatOptions ), https://tc39.es/ecma402/#sec-formatdatetimepattern
|
||||
|
|
@ -162,7 +162,7 @@ ThrowCompletionOr<GC::Ref<Array>> format_date_time_to_parts(VM& vm, DateTimeForm
|
|||
auto object = Object::create(realm, realm.intrinsics().object_prototype());
|
||||
|
||||
// b. Perform ! CreateDataPropertyOrThrow(O, "type", part.[[Type]]).
|
||||
MUST(object->create_data_property_or_throw(vm.names.type, PrimitiveString::create(vm, part.type)));
|
||||
MUST(object->create_data_property_or_throw(vm.names.type, PrimitiveString::create(vm, move(part.type))));
|
||||
|
||||
// c. Perform ! CreateDataPropertyOrThrow(O, "value", part.[[Value]]).
|
||||
MUST(object->create_data_property_or_throw(vm.names.value, PrimitiveString::create(vm, move(part.value))));
|
||||
|
|
@ -249,13 +249,13 @@ ThrowCompletionOr<GC::Ref<Array>> format_date_time_range_to_parts(VM& vm, DateTi
|
|||
auto object = Object::create(realm, realm.intrinsics().object_prototype());
|
||||
|
||||
// b. Perform ! CreateDataPropertyOrThrow(O, "type", part.[[Type]]).
|
||||
MUST(object->create_data_property_or_throw(vm.names.type, PrimitiveString::create(vm, part.type)));
|
||||
MUST(object->create_data_property_or_throw(vm.names.type, PrimitiveString::create(vm, move(part.type))));
|
||||
|
||||
// c. Perform ! CreateDataPropertyOrThrow(O, "value", part.[[Value]]).
|
||||
MUST(object->create_data_property_or_throw(vm.names.value, PrimitiveString::create(vm, move(part.value))));
|
||||
|
||||
// d. Perform ! CreateDataPropertyOrThrow(O, "source", part.[[Source]]).
|
||||
MUST(object->create_data_property_or_throw(vm.names.source, PrimitiveString::create(vm, part.source)));
|
||||
MUST(object->create_data_property_or_throw(vm.names.source, PrimitiveString::create(vm, move(part.source))));
|
||||
|
||||
// e. Perform ! CreateDataProperty(result, ! ToString(n), O).
|
||||
MUST(result->create_data_property_or_throw(n, object));
|
||||
|
|
@ -535,7 +535,8 @@ static double to_epoch_milliseconds(Crypto::SignedBigInteger const& epoch_nanose
|
|||
ThrowCompletionOr<ValueFormat> handle_date_time_temporal_date(VM& vm, DateTimeFormat& date_time_format, Temporal::PlainDate const& temporal_date)
|
||||
{
|
||||
// 1. If temporalDate.[[Calendar]] is not either dateTimeFormat.[[Calendar]] or "iso8601", throw a RangeError exception.
|
||||
if (!temporal_date.calendar().is_one_of(date_time_format.calendar(), "iso8601"sv))
|
||||
auto date_time_format_calendar = date_time_format.calendar().utf16_view().bytes();
|
||||
if (!temporal_date.calendar().is_one_of(date_time_format_calendar, "iso8601"sv))
|
||||
return vm.throw_completion<RangeError>(ErrorType::IntlTemporalInvalidCalendar, "Temporal.PlainDate"sv, temporal_date.calendar(), date_time_format.calendar());
|
||||
|
||||
// 2. Let isoDateTime be CombineISODateAndTimeRecord(temporalDate.[[ISODate]], NoonTimeRecord()).
|
||||
|
|
@ -559,7 +560,7 @@ ThrowCompletionOr<ValueFormat> handle_date_time_temporal_date(VM& vm, DateTimeFo
|
|||
ThrowCompletionOr<ValueFormat> handle_date_time_temporal_year_month(VM& vm, DateTimeFormat& date_time_format, Temporal::PlainYearMonth const& temporal_year_month)
|
||||
{
|
||||
// 1. If temporalYearMonth.[[Calendar]] is not equal to dateTimeFormat.[[Calendar]], throw a RangeError exception.
|
||||
if (temporal_year_month.calendar() != date_time_format.calendar())
|
||||
if (temporal_year_month.calendar() != date_time_format.calendar().utf16_view().bytes())
|
||||
return vm.throw_completion<RangeError>(ErrorType::IntlTemporalInvalidCalendar, "Temporal.PlainYearMonth"sv, temporal_year_month.calendar(), date_time_format.calendar());
|
||||
|
||||
// 2. Let isoDateTime be CombineISODateAndTimeRecord(temporalYearMonth.[[ISODate]], NoonTimeRecord()).
|
||||
|
|
@ -583,7 +584,7 @@ ThrowCompletionOr<ValueFormat> handle_date_time_temporal_year_month(VM& vm, Date
|
|||
ThrowCompletionOr<ValueFormat> handle_date_time_temporal_month_day(VM& vm, DateTimeFormat& date_time_format, Temporal::PlainMonthDay const& temporal_month_day)
|
||||
{
|
||||
// 1. If temporalMonthDay.[[Calendar]] is not equal to dateTimeFormat.[[Calendar]], throw a RangeError exception.
|
||||
if (temporal_month_day.calendar() != date_time_format.calendar())
|
||||
if (temporal_month_day.calendar() != date_time_format.calendar().utf16_view().bytes())
|
||||
return vm.throw_completion<RangeError>(ErrorType::IntlTemporalInvalidCalendar, "Temporal.PlainMonthDay"sv, temporal_month_day.calendar(), date_time_format.calendar());
|
||||
|
||||
// 2. Let isoDateTime be CombineISODateAndTimeRecord(temporalMonthDay.[[ISODate]], NoonTimeRecord()).
|
||||
|
|
@ -630,7 +631,8 @@ ThrowCompletionOr<ValueFormat> handle_date_time_temporal_time(VM& vm, DateTimeFo
|
|||
ThrowCompletionOr<ValueFormat> handle_date_time_temporal_date_time(VM& vm, DateTimeFormat& date_time_format, Temporal::PlainDateTime const& date_time)
|
||||
{
|
||||
// 1. If dateTime.[[Calendar]] is not "iso8601" and not equal to dateTimeFormat.[[Calendar]], throw a RangeError exception.
|
||||
if (!date_time.calendar().is_one_of(date_time_format.calendar(), "iso8601"sv))
|
||||
auto date_time_format_calendar = date_time_format.calendar().utf16_view().bytes();
|
||||
if (!date_time.calendar().is_one_of(date_time_format_calendar, "iso8601"sv))
|
||||
return vm.throw_completion<RangeError>(ErrorType::IntlTemporalInvalidCalendar, "Temporal.PlainDateTime"sv, date_time.calendar(), date_time_format.calendar());
|
||||
|
||||
// 2. Let epochNs be GetUTCEpochNanoseconds(dateTime.[[ISODateTime]]).
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <AK/String.h>
|
||||
#include <AK/StringView.h>
|
||||
#include <AK/Types.h>
|
||||
#include <AK/Utf16String.h>
|
||||
#include <AK/Utf16View.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibJS/Runtime/Completion.h>
|
||||
|
|
@ -29,32 +30,32 @@ class DateTimeFormat final : public IntlObject {
|
|||
public:
|
||||
virtual ~DateTimeFormat() override = default;
|
||||
|
||||
virtual ReadonlySpan<StringView> relevant_extension_keys() const override;
|
||||
virtual ReadonlySpan<Utf16View> relevant_extension_keys() const override;
|
||||
virtual ReadonlySpan<ResolutionOptionDescriptor> resolution_option_descriptors(VM&) const override;
|
||||
|
||||
String const& locale() const { return m_locale; }
|
||||
void set_locale(String locale) { m_locale = move(locale); }
|
||||
Utf16String const& locale() const { return m_locale; }
|
||||
void set_locale(Utf16String locale) { m_locale = move(locale); }
|
||||
|
||||
String const& icu_locale() const { return m_icu_locale; }
|
||||
void set_icu_locale(String icu_locale) { m_icu_locale = move(icu_locale); }
|
||||
Utf16String const& icu_locale() const { return m_icu_locale; }
|
||||
void set_icu_locale(Utf16String icu_locale) { m_icu_locale = move(icu_locale); }
|
||||
|
||||
String const& calendar() const { return m_calendar; }
|
||||
void set_calendar(String calendar) { m_calendar = move(calendar); }
|
||||
Utf16String const& calendar() const { return m_calendar; }
|
||||
void set_calendar(Utf16String calendar) { m_calendar = move(calendar); }
|
||||
|
||||
String const& numbering_system() const { return m_numbering_system; }
|
||||
void set_numbering_system(String numbering_system) { m_numbering_system = move(numbering_system); }
|
||||
Utf16String const& numbering_system() const { return m_numbering_system; }
|
||||
void set_numbering_system(Utf16String numbering_system) { m_numbering_system = move(numbering_system); }
|
||||
|
||||
String const& time_zone() const { return m_time_zone; }
|
||||
void set_time_zone(String time_zone) { m_time_zone = move(time_zone); }
|
||||
Utf16String const& time_zone() const { return m_time_zone; }
|
||||
void set_time_zone(Utf16String time_zone) { m_time_zone = move(time_zone); }
|
||||
|
||||
bool has_date_style() const { return m_date_style.has_value(); }
|
||||
Optional<Unicode::DateTimeStyle> const& date_style() const { return m_date_style; }
|
||||
StringView date_style_string() const { return Unicode::date_time_style_to_string(*m_date_style); }
|
||||
Utf16String date_style_string() const { return Unicode::date_time_style_to_string(*m_date_style); }
|
||||
void set_date_style(Utf16View style) { m_date_style = Unicode::date_time_style_from_string(style); }
|
||||
|
||||
bool has_time_style() const { return m_time_style.has_value(); }
|
||||
Optional<Unicode::DateTimeStyle> const& time_style() const { return m_time_style; }
|
||||
StringView time_style_string() const { return Unicode::date_time_style_to_string(*m_time_style); }
|
||||
Utf16String time_style_string() const { return Unicode::date_time_style_to_string(*m_time_style); }
|
||||
void set_time_style(Utf16View style) { m_time_style = Unicode::date_time_style_from_string(style); }
|
||||
|
||||
Unicode::CalendarPattern& date_time_format() { return m_date_time_format; }
|
||||
|
|
@ -84,17 +85,17 @@ public:
|
|||
Optional<Unicode::DateTimeFormat const&> temporal_instant_formatter();
|
||||
void set_temporal_instant_format(Optional<Unicode::CalendarPattern> temporal_instant_format) { m_temporal_instant_format = move(temporal_instant_format); }
|
||||
|
||||
void set_temporal_time_zone(String temporal_time_zone) { m_temporal_time_zone = move(temporal_time_zone); }
|
||||
void set_temporal_time_zone(Utf16String temporal_time_zone) { m_temporal_time_zone = move(temporal_time_zone); }
|
||||
|
||||
private:
|
||||
explicit DateTimeFormat(Object& prototype);
|
||||
|
||||
virtual void visit_edges(Visitor&) override;
|
||||
|
||||
String m_locale; // [[Locale]]
|
||||
String m_calendar; // [[Calendar]]
|
||||
String m_numbering_system; // [[NumberingSystem]]
|
||||
String m_time_zone; // [[TimeZone]]
|
||||
Utf16String m_locale; // [[Locale]]
|
||||
Utf16String m_calendar; // [[Calendar]]
|
||||
Utf16String m_numbering_system; // [[NumberingSystem]]
|
||||
Utf16String m_time_zone; // [[TimeZone]]
|
||||
Optional<Unicode::DateTimeStyle> m_date_style; // [[DateStyle]]
|
||||
Optional<Unicode::DateTimeStyle> m_time_style; // [[TimeStyle]]
|
||||
Unicode::CalendarPattern m_date_time_format; // [[DateTimeFormat]]
|
||||
|
|
@ -107,7 +108,7 @@ private:
|
|||
GC::Ptr<NativeFunction> m_bound_format; // [[BoundFormat]]
|
||||
|
||||
// Non-standard. Stores the ICU date-time formatters for the Intl object's formatting options.
|
||||
String m_icu_locale;
|
||||
Utf16String m_icu_locale;
|
||||
OwnPtr<Unicode::DateTimeFormat> m_formatter;
|
||||
OwnPtr<Unicode::DateTimeFormat> m_temporal_plain_date_formatter;
|
||||
OwnPtr<Unicode::DateTimeFormat> m_temporal_plain_year_month_formatter;
|
||||
|
|
@ -115,7 +116,7 @@ private:
|
|||
OwnPtr<Unicode::DateTimeFormat> m_temporal_plain_time_formatter;
|
||||
OwnPtr<Unicode::DateTimeFormat> m_temporal_plain_date_time_formatter;
|
||||
OwnPtr<Unicode::DateTimeFormat> m_temporal_instant_formatter;
|
||||
String m_temporal_time_zone;
|
||||
Utf16String m_temporal_time_zone;
|
||||
};
|
||||
|
||||
using FormattableDateTime = Variant<
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ JS_DEFINE_NATIVE_FUNCTION(DateTimeFormatConstructor::supported_locales_of)
|
|||
// 11.1.2 CreateDateTimeFormat ( newTarget, locales, options, required, defaults ), https://tc39.es/ecma402/#sec-createdatetimeformat
|
||||
// 15.4.1 CreateDateTimeFormat ( newTarget, locales, options, required, defaults [ , toLocaleStringTimeZone ] ), https://tc39.es/proposal-temporal/#sec-createdatetimeformat
|
||||
// 3.1.1 CreateDateTimeFormat ( newTarget, locales, options, required, defaults ), https://tc39.es/proposal-intl-era-monthcode/#sec-ecma402-intl-datetimeformat-constructor
|
||||
ThrowCompletionOr<GC::Ref<DateTimeFormat>> create_date_time_format(VM& vm, FunctionObject& new_target, Value locales_value, Value options_value, OptionRequired required, OptionDefaults defaults, Optional<String> const& to_locale_string_time_zone)
|
||||
ThrowCompletionOr<GC::Ref<DateTimeFormat>> create_date_time_format(VM& vm, FunctionObject& new_target, Value locales_value, Value options_value, OptionRequired required, OptionDefaults defaults, Optional<Utf16View> const& to_locale_string_time_zone)
|
||||
{
|
||||
// 1. Let dateTimeFormat be ? OrdinaryCreateFromConstructor(newTarget, "%Intl.DateTimeFormat.prototype%", « [[InitializedDateTimeFormat]], [[Locale]], [[Calendar]], [[NumberingSystem]], [[TimeZone]], [[HourCycle]], [[DateStyle]], [[TimeStyle]], [[DateTimeFormat]], [[BoundFormat]] »).
|
||||
auto date_time_format = TRY(ordinary_create_from_constructor<DateTimeFormat>(vm, new_target, &Intrinsics::intl_date_time_format_prototype));
|
||||
|
|
@ -115,27 +115,27 @@ ThrowCompletionOr<GC::Ref<DateTimeFormat>> create_date_time_format(VM& vm, Funct
|
|||
date_time_format->set_locale(move(result.locale));
|
||||
|
||||
// 8. Let resolvedCalendar be r.[[ca]].
|
||||
if (auto* resolved_calendar = result.ca.get_pointer<String>()) {
|
||||
if (auto* resolved_calendar = result.ca.get_pointer<Utf16String>()) {
|
||||
// 9. If resolvedCalendar is "islamic", then
|
||||
// NB: We also make "islamic-rgsa" fall back to "islamic-tbla", as test262 relies on this behavior. This falls
|
||||
// within implementation-defined behavior. See:
|
||||
// https://github.com/tc39/ecma402/pull/1044#discussion_r2926804980
|
||||
if (resolved_calendar->is_one_of("islamic"sv, "islamic-rgsa"sv)) {
|
||||
if (resolved_calendar->utf16_view().is_one_of("islamic"sv, "islamic-rgsa"sv)) {
|
||||
// a. Set resolvedCalendar to "islamic-tbla".
|
||||
*resolved_calendar = "islamic-tbla"_string;
|
||||
date_time_format->set_calendar("islamic-tbla"_utf16);
|
||||
|
||||
// b. If the ECMAScript implementation has a mechanism for reporting diagnostic warning messages, a warning
|
||||
// should be issued.
|
||||
}
|
||||
|
||||
} else {
|
||||
// 10. Set dateTimeFormat.[[Calendar]] to resolvedCalendar.
|
||||
date_time_format->set_calendar(move(*resolved_calendar));
|
||||
}
|
||||
}
|
||||
|
||||
date_time_format->set_icu_locale(move(result.icu_locale));
|
||||
|
||||
// 11. Set dateTimeFormat.[[NumberingSystem]] to r.[[nu]].
|
||||
if (auto* resolved_numbering_system = result.nu.get_pointer<String>())
|
||||
if (auto* resolved_numbering_system = result.nu.get_pointer<Utf16String>())
|
||||
date_time_format->set_numbering_system(move(*resolved_numbering_system));
|
||||
|
||||
// 12. Let resolvedLocaleData be r.[[LocaleData]].
|
||||
|
|
@ -157,12 +157,12 @@ ThrowCompletionOr<GC::Ref<DateTimeFormat>> create_date_time_format(VM& vm, Funct
|
|||
VERIFY(hour12.is_undefined());
|
||||
|
||||
// b. Let hc be r.[[hc]].
|
||||
if (auto* resolved_hour_cycle = result.hc.get_pointer<String>())
|
||||
hour_cycle_value = Unicode::hour_cycle_from_string(*resolved_hour_cycle);
|
||||
if (auto* resolved_hour_cycle = result.hc.get_pointer<Utf16String>())
|
||||
hour_cycle_value = Unicode::hour_cycle_from_string(resolved_hour_cycle->utf16_view());
|
||||
|
||||
// c. If hc is null, set hc to resolvedLocaleData.[[hourCycle]].
|
||||
if (!hour_cycle_value.has_value())
|
||||
hour_cycle_value = Unicode::default_hour_cycle(date_time_format->locale());
|
||||
hour_cycle_value = Unicode::default_hour_cycle(date_time_format->icu_locale().utf16_view());
|
||||
}
|
||||
|
||||
// 16. Set dateTimeFormat.[[HourCycle]] to hc.
|
||||
|
|
@ -170,22 +170,21 @@ ThrowCompletionOr<GC::Ref<DateTimeFormat>> create_date_time_format(VM& vm, Funct
|
|||
|
||||
// 17. Let timeZone be ? Get(options, "timeZone").
|
||||
auto time_zone_value = TRY(options->get(vm.names.timeZone));
|
||||
String time_zone;
|
||||
Utf16String time_zone_string;
|
||||
Utf16String icu_time_zone;
|
||||
Utf16String time_zone;
|
||||
|
||||
// 18. If timeZone is undefined, then
|
||||
if (time_zone_value.is_undefined()) {
|
||||
// a. If toLocaleStringTimeZone is present, then
|
||||
if (to_locale_string_time_zone.has_value()) {
|
||||
// i. Set timeZone to toLocaleStringTimeZone.
|
||||
time_zone = *to_locale_string_time_zone;
|
||||
time_zone_string = Utf16String::from_utf8(time_zone);
|
||||
time_zone = Utf16String::from_utf16(*to_locale_string_time_zone);
|
||||
}
|
||||
// b. Else,
|
||||
else {
|
||||
// i. Set timeZone to SystemTimeZoneIdentifier().
|
||||
time_zone = system_time_zone_identifier();
|
||||
time_zone_string = Utf16String::from_utf8(time_zone);
|
||||
icu_time_zone = time_zone;
|
||||
}
|
||||
}
|
||||
// 19. Else,
|
||||
|
|
@ -195,10 +194,10 @@ ThrowCompletionOr<GC::Ref<DateTimeFormat>> create_date_time_format(VM& vm, Funct
|
|||
return vm.throw_completion<TypeError>(ErrorType::IntlInvalidDateTimeFormatOption, vm.names.timeZone, "a toLocaleString time zone"sv);
|
||||
|
||||
// b. Set timeZone to ? ToString(timeZone).
|
||||
time_zone_string = TRY(time_zone_value.to_utf16_string(vm));
|
||||
time_zone = TRY(time_zone_value.to_utf16_string(vm));
|
||||
}
|
||||
|
||||
auto time_zone_view = time_zone_string.utf16_view();
|
||||
auto time_zone_view = time_zone.utf16_view();
|
||||
|
||||
// 20. If IsTimeZoneOffsetString(timeZone) is true, then
|
||||
auto parse_result = Temporal::parse_utc_offset(time_zone_view, Temporal::SubMinutePrecision::No);
|
||||
|
|
@ -218,33 +217,31 @@ ThrowCompletionOr<GC::Ref<DateTimeFormat>> create_date_time_format(VM& vm, Funct
|
|||
|
||||
// e. Set timeZone to FormatOffsetTimeZoneIdentifier(offsetMinutes).
|
||||
time_zone = format_offset_time_zone_identifier(offset_minutes);
|
||||
icu_time_zone = time_zone;
|
||||
}
|
||||
// 21. Else,
|
||||
else {
|
||||
// a. Let timeZoneIdentifierRecord be GetAvailableNamedTimeZoneIdentifier(timeZone).
|
||||
if (!time_zone_view.is_ascii())
|
||||
return vm.throw_completion<RangeError>(ErrorType::OptionIsNotValidValue, time_zone_view, vm.names.timeZone);
|
||||
|
||||
time_zone = MUST(time_zone_view.to_utf8());
|
||||
auto time_zone_identifier_record = get_available_named_time_zone_identifier(time_zone);
|
||||
auto time_zone_identifier_record = get_available_named_time_zone_identifier(time_zone_view);
|
||||
|
||||
// b. If timeZoneIdentifierRecord is EMPTY, throw a RangeError exception.
|
||||
if (!time_zone_identifier_record.has_value())
|
||||
return vm.throw_completion<RangeError>(ErrorType::OptionIsNotValidValue, time_zone, vm.names.timeZone);
|
||||
return vm.throw_completion<RangeError>(ErrorType::OptionIsNotValidValue, time_zone_view, vm.names.timeZone);
|
||||
|
||||
// c. Set timeZone to timeZoneIdentifierRecord.[[Identifier]].
|
||||
time_zone = time_zone_identifier_record->identifier;
|
||||
icu_time_zone = time_zone;
|
||||
}
|
||||
|
||||
// 22. Set dateTimeFormat.[[TimeZone]] to timeZone.
|
||||
date_time_format->set_time_zone(time_zone);
|
||||
date_time_format->set_time_zone(move(time_zone));
|
||||
|
||||
// NOTE: ICU requires time zone offset strings to be of the form "GMT+00:00"
|
||||
if (is_time_zone_offset_string)
|
||||
time_zone = MUST(String::formatted("GMT{}", time_zone));
|
||||
icu_time_zone = Utf16String::formatted("GMT{}", icu_time_zone);
|
||||
|
||||
// AD-HOC: We must store the massaged time zone for creating ICU formatters for Temporal objects.
|
||||
date_time_format->set_temporal_time_zone(time_zone);
|
||||
date_time_format->set_temporal_time_zone(icu_time_zone);
|
||||
|
||||
// 23. Let formatOptions be a new Record.
|
||||
Unicode::CalendarPattern format_options {};
|
||||
|
|
@ -297,7 +294,7 @@ ThrowCompletionOr<GC::Ref<DateTimeFormat>> create_date_time_format(VM& vm, Funct
|
|||
}));
|
||||
|
||||
// 27. Let formatMatcher be ? GetOption(options, "formatMatcher", string, « "basic", "best fit" », "best fit").
|
||||
[[maybe_unused]] auto format_matcher = TRY(get_option(vm, *options, vm.names.formatMatcher, OptionType::String, AK::Array { "basic"sv, "best fit"sv }, "best fit"sv));
|
||||
[[maybe_unused]] auto format_matcher = TRY(get_option(vm, *options, vm.names.formatMatcher, OptionType::String, AK::Array { "basic"sv, "best fit"sv }, u"best fit"sv));
|
||||
|
||||
// 28. Let dateStyle be ? GetOption(options, "dateStyle", string, « "full", "long", "medium", "short" », undefined).
|
||||
auto date_style = TRY(get_option(vm, *options, vm.names.dateStyle, OptionType::String, AK::Array { "full"sv, "long"sv, "medium"sv, "short"sv }, Empty {}));
|
||||
|
|
@ -340,8 +337,8 @@ ThrowCompletionOr<GC::Ref<DateTimeFormat>> create_date_time_format(VM& vm, Funct
|
|||
// d. Let styles be resolvedLocaleData.[[styles]].[[<resolvedCalendar>]].
|
||||
// e. Let bestFormat be DateTimeStyleFormat(dateStyle, timeStyle, styles).
|
||||
formatter = Unicode::DateTimeFormat::create_for_date_and_time_style(
|
||||
date_time_format->icu_locale(),
|
||||
time_zone,
|
||||
date_time_format->icu_locale().utf16_view().bytes(),
|
||||
icu_time_zone.utf16_view().bytes(),
|
||||
format_options.hour_cycle,
|
||||
format_options.hour12,
|
||||
date_time_format->date_style(),
|
||||
|
|
@ -428,8 +425,8 @@ ThrowCompletionOr<GC::Ref<DateTimeFormat>> create_date_time_format(VM& vm, Funct
|
|||
}
|
||||
|
||||
formatter = Unicode::DateTimeFormat::create_for_pattern_options(
|
||||
date_time_format->icu_locale(),
|
||||
time_zone,
|
||||
date_time_format->icu_locale().utf16_view().bytes(),
|
||||
icu_time_zone.utf16_view().bytes(),
|
||||
best_format);
|
||||
}
|
||||
|
||||
|
|
@ -444,7 +441,7 @@ ThrowCompletionOr<GC::Ref<DateTimeFormat>> create_date_time_format(VM& vm, Funct
|
|||
}
|
||||
|
||||
// 11.1.3 FormatOffsetTimeZoneIdentifier ( offsetMinutes ), https://tc39.es/ecma402/#sec-formatoffsettimezoneidentifier
|
||||
String format_offset_time_zone_identifier(double offset_minutes)
|
||||
Utf16String format_offset_time_zone_identifier(double offset_minutes)
|
||||
{
|
||||
// 1. If offsetMinutes ≥ 0, let sign be the code unit 0x002B (PLUS SIGN); otherwise, let sign be the code unit 0x002D (HYPHEN-MINUS).
|
||||
auto sign = offset_minutes >= 0.0 ? '+' : '-';
|
||||
|
|
@ -459,7 +456,7 @@ String format_offset_time_zone_identifier(double offset_minutes)
|
|||
auto minutes = static_cast<i64>(modulo(absolute_minutes, 60.0));
|
||||
|
||||
// 5. Return the string-concatenation of sign, ToZeroPaddedDecimalString(hours, 2), the code unit 0x003A (COLON), and ToZeroPaddedDecimalString(minutes, 2).
|
||||
return MUST(String::formatted("{}{:02}:{:02}", sign, hours, minutes));
|
||||
return Utf16String::formatted("{}{:02}:{:02}", sign, hours, minutes);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ enum class OptionInherit {
|
|||
Relevant,
|
||||
};
|
||||
|
||||
ThrowCompletionOr<GC::Ref<DateTimeFormat>> create_date_time_format(VM&, FunctionObject& new_target, Value locales_value, Value options_value, OptionRequired, OptionDefaults, Optional<String> const& to_locale_string_time_zone = {});
|
||||
String format_offset_time_zone_identifier(double offset_minutes);
|
||||
ThrowCompletionOr<GC::Ref<DateTimeFormat>> create_date_time_format(VM&, FunctionObject& new_target, Value locales_value, Value options_value, OptionRequired, OptionDefaults, Optional<Utf16View> const& to_locale_string_time_zone = {});
|
||||
Utf16String format_offset_time_zone_identifier(double offset_minutes);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ void DateTimeFormatFunction::initialize(Realm& realm)
|
|||
|
||||
Base::initialize(realm);
|
||||
define_direct_property(vm.names.length, Value(1), Attribute::Configurable);
|
||||
define_direct_property(vm.names.name, PrimitiveString::create(vm, String {}), Attribute::Configurable);
|
||||
define_direct_property(vm.names.name, PrimitiveString::create(vm, Utf16String {}), Attribute::Configurable);
|
||||
}
|
||||
|
||||
ThrowCompletionOr<Value> DateTimeFormatFunction::call()
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ void DateTimeFormatPrototype::initialize(Realm& realm)
|
|||
auto& vm = this->vm();
|
||||
|
||||
// 11.3.7 Intl.DateTimeFormat.prototype [ %Symbol.toStringTag% ], https://tc39.es/ecma402/#sec-intl.datetimeformat.prototype-%symbol.tostringtag%
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Intl.DateTimeFormat"_string), Attribute::Configurable);
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Intl.DateTimeFormat"_utf16_fly_string), Attribute::Configurable);
|
||||
|
||||
define_native_accessor(realm, vm.names.format, format, nullptr, Attribute::Configurable);
|
||||
|
||||
|
|
@ -104,7 +104,7 @@ JS_DEFINE_NATIVE_FUNCTION(DateTimeFormatPrototype::resolved_options)
|
|||
MUST(options->create_data_property_or_throw(property, Value(*option)));
|
||||
} else {
|
||||
auto name = Unicode::calendar_pattern_style_to_string(*option);
|
||||
MUST(options->create_data_property_or_throw(property, PrimitiveString::create(vm, name)));
|
||||
MUST(options->create_data_property_or_throw(property, PrimitiveString::create(vm, move(name))));
|
||||
}
|
||||
|
||||
return {};
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ DisplayNames::DisplayNames(Object& prototype)
|
|||
}
|
||||
|
||||
// 12.2.3 Internal slots, https://tc39.es/ecma402/#sec-Intl.DisplayNames-internal-slots
|
||||
ReadonlySpan<StringView> DisplayNames::relevant_extension_keys() const
|
||||
ReadonlySpan<Utf16View> DisplayNames::relevant_extension_keys() const
|
||||
{
|
||||
// The value of the [[RelevantExtensionKeys]] internal slot is « ».
|
||||
return {};
|
||||
|
|
@ -50,21 +50,21 @@ void DisplayNames::set_type(Utf16View type)
|
|||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
StringView DisplayNames::type_string() const
|
||||
Utf16String DisplayNames::type_string() const
|
||||
{
|
||||
switch (m_type) {
|
||||
case Type::Language:
|
||||
return "language"sv;
|
||||
return "language"_utf16;
|
||||
case Type::Region:
|
||||
return "region"sv;
|
||||
return "region"_utf16;
|
||||
case Type::Script:
|
||||
return "script"sv;
|
||||
return "script"_utf16;
|
||||
case Type::Currency:
|
||||
return "currency"sv;
|
||||
return "currency"_utf16;
|
||||
case Type::Calendar:
|
||||
return "calendar"sv;
|
||||
return "calendar"_utf16;
|
||||
case Type::DateTimeField:
|
||||
return "dateTimeField"sv;
|
||||
return "dateTimeField"_utf16;
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
|
@ -80,13 +80,13 @@ void DisplayNames::set_fallback(Utf16View fallback)
|
|||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
StringView DisplayNames::fallback_string() const
|
||||
Utf16String DisplayNames::fallback_string() const
|
||||
{
|
||||
switch (m_fallback) {
|
||||
case Fallback::None:
|
||||
return "none"sv;
|
||||
return "none"_utf16;
|
||||
case Fallback::Code:
|
||||
return "code"sv;
|
||||
return "code"_utf16;
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
|
@ -97,22 +97,17 @@ ThrowCompletionOr<Value> canonical_code_for_display_names(VM& vm, DisplayNames::
|
|||
{
|
||||
// 1. If type is "language", then
|
||||
if (type == DisplayNames::Type::Language) {
|
||||
if (!code.is_ascii())
|
||||
return vm.throw_completion<RangeError>(ErrorType::OptionIsNotValidValue, code, "language"sv);
|
||||
|
||||
auto code_string = MUST(code.to_utf8());
|
||||
|
||||
// a. If code does not match the unicode_language_id production, throw a RangeError exception.
|
||||
if (!Unicode::parse_unicode_language_id(code_string).has_value())
|
||||
if (!Unicode::parse_unicode_language_id(code).has_value())
|
||||
return vm.throw_completion<RangeError>(ErrorType::OptionIsNotValidValue, code, "language"sv);
|
||||
|
||||
// b. If IsWellFormedLanguageTag(code) is false, throw a RangeError exception.
|
||||
if (!is_well_formed_language_tag(code_string))
|
||||
if (!is_well_formed_language_tag(code))
|
||||
return vm.throw_completion<RangeError>(ErrorType::IntlInvalidLanguageTag, code);
|
||||
|
||||
// c. Return ! CanonicalizeUnicodeLocaleId(code).
|
||||
auto canonicalized_tag = canonicalize_unicode_locale_id(code_string);
|
||||
return PrimitiveString::create(vm, move(canonicalized_tag));
|
||||
auto canonicalized_tag = canonicalize_unicode_locale_id(code);
|
||||
return PrimitiveString::create(vm, canonicalized_tag);
|
||||
}
|
||||
|
||||
// 2. If type is "region", then
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <AK/Optional.h>
|
||||
#include <AK/String.h>
|
||||
#include <AK/StringView.h>
|
||||
#include <AK/Utf16String.h>
|
||||
#include <AK/Utf16View.h>
|
||||
#include <LibJS/Runtime/Intl/IntlObject.h>
|
||||
#include <LibUnicode/DisplayNames.h>
|
||||
|
|
@ -39,37 +40,43 @@ class DisplayNames final : public IntlObject {
|
|||
public:
|
||||
virtual ~DisplayNames() override = default;
|
||||
|
||||
virtual ReadonlySpan<StringView> relevant_extension_keys() const override;
|
||||
virtual ReadonlySpan<Utf16View> relevant_extension_keys() const override;
|
||||
virtual ReadonlySpan<ResolutionOptionDescriptor> resolution_option_descriptors(VM&) const override;
|
||||
|
||||
String const& locale() const { return m_locale; }
|
||||
void set_locale(String locale) { m_locale = move(locale); }
|
||||
Utf16String const& locale() const { return m_locale; }
|
||||
void set_locale(Utf16String locale) { m_locale = move(locale); }
|
||||
|
||||
Utf16String const& icu_locale() const { return m_icu_locale; }
|
||||
void set_icu_locale(Utf16String icu_locale) { m_icu_locale = move(icu_locale); }
|
||||
|
||||
Unicode::Style style() const { return m_style; }
|
||||
void set_style(Utf16View style) { m_style = Unicode::style_from_string(style); }
|
||||
StringView style_string() const { return Unicode::style_to_string(m_style); }
|
||||
Utf16String style_string() const { return Unicode::style_to_string(m_style); }
|
||||
|
||||
Type type() const { return m_type; }
|
||||
void set_type(Utf16View type);
|
||||
StringView type_string() const;
|
||||
Utf16String type_string() const;
|
||||
|
||||
Fallback fallback() const { return m_fallback; }
|
||||
void set_fallback(Utf16View fallback);
|
||||
StringView fallback_string() const;
|
||||
Utf16String fallback_string() const;
|
||||
|
||||
bool has_language_display() const { return m_language_display.has_value(); }
|
||||
Unicode::LanguageDisplay language_display() const { return *m_language_display; }
|
||||
void set_language_display(Utf16View language_display) { m_language_display = Unicode::language_display_from_string(language_display); }
|
||||
StringView language_display_string() const { return Unicode::language_display_to_string(*m_language_display); }
|
||||
Utf16String language_display_string() const { return Unicode::language_display_to_string(*m_language_display); }
|
||||
|
||||
private:
|
||||
explicit DisplayNames(Object& prototype);
|
||||
|
||||
String m_locale; // [[Locale]]
|
||||
Utf16String m_locale; // [[Locale]]
|
||||
Unicode::Style m_style { Unicode::Style::Long }; // [[Style]]
|
||||
Type m_type { Type::Invalid }; // [[Type]]
|
||||
Fallback m_fallback { Fallback::Invalid }; // [[Fallback]]
|
||||
Optional<Unicode::LanguageDisplay> m_language_display; // [[LanguageDisplay]]
|
||||
|
||||
// Non-standard. Stores the ICU locale for display-name lookups.
|
||||
Utf16String m_icu_locale;
|
||||
};
|
||||
|
||||
ThrowCompletionOr<Value> canonical_code_for_display_names(VM&, DisplayNames::Type, Utf16View code);
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ ThrowCompletionOr<GC::Ref<Object>> DisplayNamesConstructor::construct(FunctionOb
|
|||
auto [options, result, _] = TRY(resolve_options(vm, display_names, locales_value, options_value, SpecialBehaviors::RequireOptions));
|
||||
|
||||
// 6. Let style be ? GetOption(options, "style", string, « "narrow", "short", "long" », "long").
|
||||
auto style = TRY(get_option(vm, *options, vm.names.style, OptionType::String, { "narrow"sv, "short"sv, "long"sv }, "long"sv));
|
||||
auto style = TRY(get_option(vm, *options, vm.names.style, OptionType::String, { "narrow"sv, "short"sv, "long"sv }, u"long"sv));
|
||||
|
||||
// 7. Set displayNames.[[Style]] to style.
|
||||
display_names->set_style(style.as_string().utf16_string_view());
|
||||
|
|
@ -77,20 +77,21 @@ ThrowCompletionOr<GC::Ref<Object>> DisplayNamesConstructor::construct(FunctionOb
|
|||
display_names->set_type(type.as_string().utf16_string_view());
|
||||
|
||||
// 11. Let fallback be ? GetOption(options, "fallback", string, « "code", "none" », "code").
|
||||
auto fallback = TRY(get_option(vm, *options, vm.names.fallback, OptionType::String, { "code"sv, "none"sv }, "code"sv));
|
||||
auto fallback = TRY(get_option(vm, *options, vm.names.fallback, OptionType::String, { "code"sv, "none"sv }, u"code"sv));
|
||||
|
||||
// 12. Set displayNames.[[Fallback]] to fallback.
|
||||
display_names->set_fallback(fallback.as_string().utf16_string_view());
|
||||
|
||||
// 13. Set displayNames.[[Locale]] to r.[[Locale]].
|
||||
display_names->set_locale(move(result.locale));
|
||||
display_names->set_icu_locale(move(result.icu_locale));
|
||||
|
||||
// 14. Let resolvedLocaleData be r.[[LocaleData]].
|
||||
// 15. Let types be resolvedLocaleData.[[types]].
|
||||
// 16. Assert: types is a Record (see 12.2.3).
|
||||
|
||||
// 17. Let languageDisplay be ? GetOption(options, "languageDisplay", string, « "dialect", "standard" », "dialect").
|
||||
auto language_display = TRY(get_option(vm, *options, vm.names.languageDisplay, OptionType::String, { "dialect"sv, "standard"sv }, "dialect"sv));
|
||||
auto language_display = TRY(get_option(vm, *options, vm.names.languageDisplay, OptionType::String, { "dialect"sv, "standard"sv }, u"dialect"sv));
|
||||
|
||||
// 18. Let typeFields be types.[[<type>]].
|
||||
// 19. Assert: typeFields is a Record (see 12.2.3).
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ void DisplayNamesPrototype::initialize(Realm& realm)
|
|||
auto& vm = this->vm();
|
||||
|
||||
// 12.3.4 Intl.DisplayNames.prototype [ %Symbol.toStringTag% ], https://tc39.es/ecma402/#sec-intl.displaynames.prototype-%symbol.tostringtag%
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Intl.DisplayNames"_string), Attribute::Configurable);
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Intl.DisplayNames"_utf16_fly_string), Attribute::Configurable);
|
||||
|
||||
u8 attr = Attribute::Writable | Attribute::Configurable;
|
||||
define_native_function(realm, vm.names.resolvedOptions, resolved_options, 0, attr);
|
||||
|
|
@ -78,7 +78,7 @@ JS_DEFINE_NATIVE_FUNCTION(DisplayNamesPrototype::of)
|
|||
|
||||
// 4. Let code be ? CanonicalCodeForDisplayNames(displayNames.[[Type]], code).
|
||||
code = TRY(canonical_code_for_display_names(vm, display_names->type(), code.as_string().utf16_string_view()));
|
||||
auto code_string = MUST(code.as_string().utf16_string_view().to_utf8());
|
||||
auto code_view = code.as_string().utf16_string_view();
|
||||
|
||||
// 5. Let fields be displayNames.[[Fields]].
|
||||
// 6. If fields has a field [[<code>]], return fields.[[<code>]].
|
||||
|
|
@ -86,22 +86,22 @@ JS_DEFINE_NATIVE_FUNCTION(DisplayNamesPrototype::of)
|
|||
|
||||
switch (display_names->type()) {
|
||||
case DisplayNames::Type::Language:
|
||||
result = Unicode::language_display_name(display_names->locale(), code_string, display_names->language_display());
|
||||
result = Unicode::language_display_name(display_names->icu_locale().utf16_view().bytes(), code_view, display_names->language_display());
|
||||
break;
|
||||
case DisplayNames::Type::Region:
|
||||
result = Unicode::region_display_name(display_names->locale(), code_string);
|
||||
result = Unicode::region_display_name(display_names->icu_locale().utf16_view().bytes(), code_view);
|
||||
break;
|
||||
case DisplayNames::Type::Script:
|
||||
result = Unicode::script_display_name(display_names->locale(), code_string);
|
||||
result = Unicode::script_display_name(display_names->icu_locale().utf16_view().bytes(), code_view);
|
||||
break;
|
||||
case DisplayNames::Type::Currency:
|
||||
result = Unicode::currency_display_name(display_names->locale(), code_string, display_names->style());
|
||||
result = Unicode::currency_display_name(display_names->icu_locale().utf16_view().bytes(), code_view, display_names->style());
|
||||
break;
|
||||
case DisplayNames::Type::Calendar:
|
||||
result = Unicode::calendar_display_name(display_names->locale(), code_string);
|
||||
result = Unicode::calendar_display_name(display_names->icu_locale().utf16_view().bytes(), code_view);
|
||||
break;
|
||||
case DisplayNames::Type::DateTimeField:
|
||||
result = Unicode::date_time_field_display_name(display_names->locale(), code_string, display_names->style());
|
||||
result = Unicode::date_time_field_display_name(display_names->icu_locale().utf16_view().bytes(), code_view, display_names->style());
|
||||
break;
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
|
|
|
|||
|
|
@ -29,10 +29,10 @@ DurationFormat::DurationFormat(Object& prototype)
|
|||
}
|
||||
|
||||
// 13.2.3 Internal slots, https://tc39.es/ecma402/#sec-Intl.DurationFormat-internal-slots
|
||||
ReadonlySpan<StringView> DurationFormat::relevant_extension_keys() const
|
||||
ReadonlySpan<Utf16View> DurationFormat::relevant_extension_keys() const
|
||||
{
|
||||
// The value of the [[RelevantExtensionKeys]] internal slot is « "nu" ».
|
||||
static constexpr AK::Array keys { "nu"sv };
|
||||
static constexpr AK::Array<Utf16View, 1> keys { "nu"sv };
|
||||
return keys;
|
||||
}
|
||||
|
||||
|
|
@ -63,17 +63,17 @@ DurationFormat::Style DurationFormat::style_from_string(Utf16View style)
|
|||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
StringView DurationFormat::style_to_string(Style style)
|
||||
Utf16String DurationFormat::style_to_string(Style style)
|
||||
{
|
||||
switch (style) {
|
||||
case Style::Long:
|
||||
return "long"sv;
|
||||
return "long"_utf16;
|
||||
case Style::Short:
|
||||
return "short"sv;
|
||||
return "short"_utf16;
|
||||
case Style::Narrow:
|
||||
return "narrow"sv;
|
||||
return "narrow"_utf16;
|
||||
case Style::Digital:
|
||||
return "digital"sv;
|
||||
return "digital"_utf16;
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
|
@ -105,32 +105,32 @@ DurationFormat::ValueStyle DurationFormat::value_style_from_string(Utf16View val
|
|||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
StringView DurationFormat::value_style_to_string(ValueStyle value_style)
|
||||
Utf16String DurationFormat::value_style_to_string(ValueStyle value_style)
|
||||
{
|
||||
switch (value_style) {
|
||||
case ValueStyle::Long:
|
||||
return "long"sv;
|
||||
return "long"_utf16;
|
||||
case ValueStyle::Short:
|
||||
return "short"sv;
|
||||
return "short"_utf16;
|
||||
case ValueStyle::Narrow:
|
||||
return "narrow"sv;
|
||||
return "narrow"_utf16;
|
||||
case ValueStyle::Numeric:
|
||||
return "numeric"sv;
|
||||
return "numeric"_utf16;
|
||||
case ValueStyle::TwoDigit:
|
||||
return "2-digit"sv;
|
||||
return "2-digit"_utf16;
|
||||
case ValueStyle::Fractional:
|
||||
return "fractional"sv;
|
||||
return "fractional"_utf16;
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
StringView DurationFormat::display_to_string(Display display)
|
||||
Utf16String DurationFormat::display_to_string(Display display)
|
||||
{
|
||||
switch (display) {
|
||||
case Display::Auto:
|
||||
return "auto"sv;
|
||||
return "auto"_utf16;
|
||||
case Display::Always:
|
||||
return "always"sv;
|
||||
return "always"_utf16;
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
|
@ -238,7 +238,7 @@ ThrowCompletionOr<DurationFormat::DurationUnitOptions> get_duration_unit_options
|
|||
DurationFormat::ValueStyle style;
|
||||
|
||||
// 2. Let displayDefault be "always".
|
||||
auto display_default = "always"sv;
|
||||
Utf16View display_default = u"always"sv;
|
||||
|
||||
// 3. If style is undefined, then
|
||||
if (style_value.is_undefined()) {
|
||||
|
|
@ -249,7 +249,7 @@ ThrowCompletionOr<DurationFormat::DurationUnitOptions> get_duration_unit_options
|
|||
|
||||
// ii. If unit is not one of "hours", "minutes", or "seconds", set displayDefault to "auto".
|
||||
if (!first_is_one_of(unit, DurationFormat::Unit::Hours, DurationFormat::Unit::Minutes, DurationFormat::Unit::Seconds))
|
||||
display_default = "auto"sv;
|
||||
display_default = u"auto"sv;
|
||||
}
|
||||
// b. Else if prevStyle is one of "fractional", "numeric" or "2-digit", then
|
||||
else if (first_is_one_of(previous_style, DurationFormat::ValueStyle::Fractional, DurationFormat::ValueStyle::Numeric, DurationFormat::ValueStyle::TwoDigit)) {
|
||||
|
|
@ -258,7 +258,7 @@ ThrowCompletionOr<DurationFormat::DurationUnitOptions> get_duration_unit_options
|
|||
|
||||
// ii. If unit is not "minutes" or "seconds", set displayDefault to "auto".
|
||||
if (!first_is_one_of(unit, DurationFormat::Unit::Minutes, DurationFormat::Unit::Seconds))
|
||||
display_default = "auto"sv;
|
||||
display_default = u"auto"sv;
|
||||
}
|
||||
// c. Else,
|
||||
else {
|
||||
|
|
@ -266,7 +266,7 @@ ThrowCompletionOr<DurationFormat::DurationUnitOptions> get_duration_unit_options
|
|||
style = static_cast<DurationFormat::ValueStyle>(base_style);
|
||||
|
||||
// ii. Set displayDefault to "auto".
|
||||
display_default = "auto"sv;
|
||||
display_default = u"auto"sv;
|
||||
}
|
||||
} else {
|
||||
style = DurationFormat::value_style_from_string(style_value.as_string().utf16_string_view());
|
||||
|
|
@ -278,7 +278,7 @@ ThrowCompletionOr<DurationFormat::DurationUnitOptions> get_duration_unit_options
|
|||
style = DurationFormat::ValueStyle::Fractional;
|
||||
|
||||
// b. Set displayDefault to "auto".
|
||||
display_default = "auto"sv;
|
||||
display_default = u"auto"sv;
|
||||
}
|
||||
|
||||
// 5. Let displayField be the string-concatenation of unit and "Display".
|
||||
|
|
@ -395,7 +395,7 @@ Vector<DurationFormatPart> format_numeric_hours(VM& vm, DurationFormat const& du
|
|||
// 8. If signDisplayed is false, then
|
||||
if (!sign_displayed) {
|
||||
// a. Perform ! CreateDataPropertyOrThrow(nfOpts, "signDisplay", "never").
|
||||
MUST(number_format_options->create_data_property_or_throw(vm.names.signDisplay, PrimitiveString::create(vm, "never"sv)));
|
||||
MUST(number_format_options->create_data_property_or_throw(vm.names.signDisplay, PrimitiveString::create(vm, "never"_utf16_fly_string)));
|
||||
}
|
||||
|
||||
// 9. Perform ! CreateDataPropertyOrThrow(nfOpts, "useGrouping", false).
|
||||
|
|
@ -412,7 +412,7 @@ Vector<DurationFormatPart> format_numeric_hours(VM& vm, DurationFormat const& du
|
|||
|
||||
for (auto& part : hours_parts) {
|
||||
// a. Append the Record { [[Type]]: part.[[Type]], [[Value]]: part.[[Value]], [[Unit]]: "hour" } to result.
|
||||
result.unchecked_append({ .type = part.type, .value = move(part.value), .unit = "hour"sv });
|
||||
result.unchecked_append({ .type = move(part.type), .value = move(part.value), .unit = "hour"_utf16 });
|
||||
}
|
||||
|
||||
// 13. Return result.
|
||||
|
|
@ -433,7 +433,7 @@ Vector<DurationFormatPart> format_numeric_minutes(VM& vm, DurationFormat const&
|
|||
auto separator = duration_format.hour_minute_separator();
|
||||
|
||||
// b. Append the Record { [[Type]]: "literal", [[Value]]: separator, [[Unit]]: EMPTY } to result.
|
||||
result.append({ .type = "literal"sv, .value = move(separator), .unit = {} });
|
||||
result.append({ .type = "literal"_utf16, .value = move(separator), .unit = {} });
|
||||
}
|
||||
|
||||
// 3. Let minutesStyle be durationFormat.[[MinutesOptions]].[[Style]].
|
||||
|
|
@ -460,7 +460,7 @@ Vector<DurationFormatPart> format_numeric_minutes(VM& vm, DurationFormat const&
|
|||
// 9. If signDisplayed is false, then
|
||||
if (!sign_displayed) {
|
||||
// a. Perform ! CreateDataPropertyOrThrow(nfOpts, "signDisplay", "never").
|
||||
MUST(number_format_options->create_data_property_or_throw(vm.names.signDisplay, PrimitiveString::create(vm, "never"sv)));
|
||||
MUST(number_format_options->create_data_property_or_throw(vm.names.signDisplay, PrimitiveString::create(vm, "never"_utf16_fly_string)));
|
||||
}
|
||||
|
||||
// 10. Perform ! CreateDataPropertyOrThrow(nfOpts, "useGrouping", false).
|
||||
|
|
@ -477,7 +477,7 @@ Vector<DurationFormatPart> format_numeric_minutes(VM& vm, DurationFormat const&
|
|||
|
||||
for (auto& part : minutes_parts) {
|
||||
// a. Append the Record { [[Type]]: part.[[Type]], [[Value]]: part.[[Value]], [[Unit]]: "minute" } to result.
|
||||
result.unchecked_append({ .type = part.type, .value = move(part.value), .unit = "minute"sv });
|
||||
result.unchecked_append({ .type = move(part.type), .value = move(part.value), .unit = "minute"_utf16 });
|
||||
}
|
||||
|
||||
// 14. Return result.
|
||||
|
|
@ -498,7 +498,7 @@ Vector<DurationFormatPart> format_numeric_seconds(VM& vm, DurationFormat const&
|
|||
auto separator = duration_format.minute_second_separator();
|
||||
|
||||
// b. Append the Record { [[Type]]: "literal", [[Value]]: separator, [[Unit]]: EMPTY } to result.
|
||||
result.append({ .type = "literal"sv, .value = move(separator), .unit = {} });
|
||||
result.append({ .type = "literal"_utf16, .value = move(separator), .unit = {} });
|
||||
}
|
||||
|
||||
// 3. Let secondsStyle be durationFormat.[[SecondsOptions]].[[Style]].
|
||||
|
|
@ -525,7 +525,7 @@ Vector<DurationFormatPart> format_numeric_seconds(VM& vm, DurationFormat const&
|
|||
// 9. If signDisplayed is false, then
|
||||
if (!sign_displayed) {
|
||||
// a. Perform ! CreateDataPropertyOrThrow(nfOpts, "signDisplay", "never").
|
||||
MUST(number_format_options->create_data_property_or_throw(vm.names.signDisplay, PrimitiveString::create(vm, "never"sv)));
|
||||
MUST(number_format_options->create_data_property_or_throw(vm.names.signDisplay, PrimitiveString::create(vm, "never"_utf16_fly_string)));
|
||||
}
|
||||
|
||||
// 10. Perform ! CreateDataPropertyOrThrow(nfOpts, "useGrouping", false).
|
||||
|
|
@ -552,7 +552,7 @@ Vector<DurationFormatPart> format_numeric_seconds(VM& vm, DurationFormat const&
|
|||
}
|
||||
|
||||
// 14. Perform ! CreateDataPropertyOrThrow(nfOpts, "roundingMode", "trunc").
|
||||
MUST(number_format_options->create_data_property_or_throw(vm.names.roundingMode, PrimitiveString::create(vm, "trunc"sv)));
|
||||
MUST(number_format_options->create_data_property_or_throw(vm.names.roundingMode, PrimitiveString::create(vm, "trunc"_utf16_fly_string)));
|
||||
|
||||
// 15. Let nf be ! Construct(%Intl.NumberFormat%, « durationFormat.[[Locale]], nfOpts »).
|
||||
auto number_format = construct_number_format(vm, duration_format, number_format_options);
|
||||
|
|
@ -565,7 +565,7 @@ Vector<DurationFormatPart> format_numeric_seconds(VM& vm, DurationFormat const&
|
|||
|
||||
for (auto& part : seconds_parts) {
|
||||
// a. Append the Record { [[Type]]: part.[[Type]], [[Value]]: part.[[Value]], [[Unit]]: "second" } to result.
|
||||
result.unchecked_append({ .type = part.type, .value = move(part.value), .unit = "second"sv });
|
||||
result.unchecked_append({ .type = move(part.type), .value = move(part.value), .unit = "second"_utf16 });
|
||||
}
|
||||
|
||||
// 18. Return result.
|
||||
|
|
@ -690,7 +690,7 @@ Vector<DurationFormatPart> format_numeric_units(VM& vm, DurationFormat const& du
|
|||
// 18. If secondsFormatted is true, then
|
||||
if (seconds_formatted) {
|
||||
// a. Let secondsParts be FormatNumericSeconds(durationFormat, secondsValue, minutesFormatted, signDisplayed).
|
||||
auto seconds_value_mv = MathematicalValue { Utf16String::from_utf8(seconds_value.to_string(9)) };
|
||||
auto seconds_value_mv = MathematicalValue { seconds_value.to_utf16_string(9) };
|
||||
auto seconds_parts = format_numeric_seconds(vm, duration_format, seconds_value_mv, minutes_formatted, sign_displayed);
|
||||
|
||||
// b. Set numericPartsList to the list-concatenation of numericPartsList and secondsParts.
|
||||
|
|
@ -718,7 +718,7 @@ Vector<DurationFormatPart> list_format_parts(VM& vm, DurationFormat const& durat
|
|||
auto list_format_options = Object::create(realm, nullptr);
|
||||
|
||||
// 2. Perform ! CreateDataPropertyOrThrow(lfOpts, "type", "unit").
|
||||
MUST(list_format_options->create_data_property_or_throw(vm.names.type, PrimitiveString::create(vm, "unit"sv)));
|
||||
MUST(list_format_options->create_data_property_or_throw(vm.names.type, PrimitiveString::create(vm, "unit"_utf16_fly_string)));
|
||||
|
||||
// 3. Let listStyle be durationFormat.[[Style]].
|
||||
auto list_style = duration_format.style();
|
||||
|
|
@ -731,7 +731,7 @@ Vector<DurationFormatPart> list_format_parts(VM& vm, DurationFormat const& durat
|
|||
|
||||
// 5. Perform ! CreateDataPropertyOrThrow(lfOpts, "style", listStyle).
|
||||
auto locale_list_style = Unicode::style_to_string(static_cast<Unicode::Style>(list_style));
|
||||
MUST(list_format_options->create_data_property_or_throw(vm.names.style, PrimitiveString::create(vm, locale_list_style)));
|
||||
MUST(list_format_options->create_data_property_or_throw(vm.names.style, PrimitiveString::create(vm, move(locale_list_style))));
|
||||
|
||||
// 6. Let lf be ! Construct(%Intl.ListFormat%, « durationFormat.[[Locale]], lfOpts »).
|
||||
auto list_format = construct_list_format(vm, duration_format, list_format_options);
|
||||
|
|
@ -792,7 +792,7 @@ Vector<DurationFormatPart> list_format_parts(VM& vm, DurationFormat const& durat
|
|||
VERIFY(list_part.type == "literal"sv);
|
||||
|
||||
// ii. Append the Record { [[Type]]: "literal", [[Value]]: listPart.[[Value]], [[Unit]]: empty } to flattenedPartsList.
|
||||
flattened_parts_list.append({ .type = "literal"sv, .value = move(list_part.value), .unit = {} });
|
||||
flattened_parts_list.append({ .type = "literal"_utf16, .value = move(list_part.value), .unit = {} });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -876,7 +876,7 @@ Vector<DurationFormatPart> partition_duration_format_pattern(VM& vm, DurationFor
|
|||
}
|
||||
|
||||
// 5. Perform ! CreateDataPropertyOrThrow(nfOpts, "roundingMode", "trunc").
|
||||
MUST(number_format_options->create_data_property_or_throw(vm.names.roundingMode, PrimitiveString::create(vm, "trunc"sv)));
|
||||
MUST(number_format_options->create_data_property_or_throw(vm.names.roundingMode, PrimitiveString::create(vm, "trunc"_utf16_fly_string)));
|
||||
|
||||
// 6. Set numericUnitFound to true.
|
||||
numeric_unit_found = true;
|
||||
|
|
@ -884,7 +884,7 @@ Vector<DurationFormatPart> partition_duration_format_pattern(VM& vm, DurationFor
|
|||
|
||||
// iii. If display is "always" or value is not 0, then
|
||||
if (display == DurationFormat::Display::Always || !value.is_zero()) {
|
||||
auto value_mv = MathematicalValue { Utf16String::from_utf8(value.to_string(9)) };
|
||||
auto value_mv = MathematicalValue { value.to_utf16_string(9) };
|
||||
|
||||
// 1. Perform ! CreateDataPropertyOrThrow(nfOpts, "numberingSystem", durationFormat.[[NumberingSystem]]).
|
||||
MUST(number_format_options->create_data_property_or_throw(vm.names.numberingSystem, PrimitiveString::create(vm, duration_format.numbering_system())));
|
||||
|
|
@ -901,18 +901,18 @@ Vector<DurationFormatPart> partition_duration_format_pattern(VM& vm, DurationFor
|
|||
// 3. Else,
|
||||
else {
|
||||
// a. Perform ! CreateDataPropertyOrThrow(nfOpts, "signDisplay", "never").
|
||||
MUST(number_format_options->create_data_property_or_throw(vm.names.signDisplay, PrimitiveString::create(vm, "never"sv)));
|
||||
MUST(number_format_options->create_data_property_or_throw(vm.names.signDisplay, PrimitiveString::create(vm, "never"_utf16_fly_string)));
|
||||
}
|
||||
|
||||
// 3. Perform ! CreateDataPropertyOrThrow(nfOpts, "style", "unit").
|
||||
MUST(number_format_options->create_data_property_or_throw(vm.names.style, PrimitiveString::create(vm, "unit"sv)));
|
||||
MUST(number_format_options->create_data_property_or_throw(vm.names.style, PrimitiveString::create(vm, "unit"_utf16_fly_string)));
|
||||
|
||||
// 4. Perform ! CreateDataPropertyOrThrow(nfOpts, "unit", numberFormatUnit).
|
||||
MUST(number_format_options->create_data_property_or_throw(vm.names.unit, PrimitiveString::create(vm, number_format_unit.as_string())));
|
||||
|
||||
// 5. Perform ! CreateDataPropertyOrThrow(nfOpts, "unitDisplay", style).
|
||||
auto locale_style = Unicode::style_to_string(static_cast<Unicode::Style>(style));
|
||||
MUST(number_format_options->create_data_property_or_throw(vm.names.unitDisplay, PrimitiveString::create(vm, locale_style)));
|
||||
MUST(number_format_options->create_data_property_or_throw(vm.names.unitDisplay, PrimitiveString::create(vm, move(locale_style))));
|
||||
|
||||
// 6. Let nf be ! Construct(%Intl.NumberFormat%, « durationFormat.[[Locale]], nfOpts »).
|
||||
auto number_format = construct_number_format(vm, duration_format, number_format_options);
|
||||
|
|
@ -925,10 +925,11 @@ Vector<DurationFormatPart> partition_duration_format_pattern(VM& vm, DurationFor
|
|||
|
||||
// 10. For each Record { [[Type]], [[Value]] } part of parts, do
|
||||
list.ensure_capacity(parts.size());
|
||||
auto unit = number_format_unit.as_string().to_utf16_string();
|
||||
|
||||
for (auto& part : parts) {
|
||||
// a. Append the Record { [[Type]]: part.[[Type]], [[Value]]: part.[[Value]], [[Unit]]: numberFormatUnit } to list.
|
||||
list.unchecked_append({ .type = part.type, .value = move(part.value), .unit = number_format_unit.as_string().view() });
|
||||
list.unchecked_append({ .type = move(part.type), .value = move(part.value), .unit = unit });
|
||||
}
|
||||
|
||||
// 11. Append list to result.
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/Array.h>
|
||||
#include <AK/String.h>
|
||||
#include <AK/Utf16String.h>
|
||||
#include <AK/Utf16View.h>
|
||||
#include <LibCrypto/BigFraction/BigFraction.h>
|
||||
#include <LibJS/Runtime/Intl/IntlObject.h>
|
||||
|
|
@ -29,7 +29,7 @@ public:
|
|||
Digital,
|
||||
};
|
||||
static Style style_from_string(Utf16View style);
|
||||
static StringView style_to_string(Style);
|
||||
static Utf16String style_to_string(Style);
|
||||
|
||||
enum class ValueStyle {
|
||||
Long,
|
||||
|
|
@ -40,7 +40,7 @@ public:
|
|||
Fractional,
|
||||
};
|
||||
static ValueStyle value_style_from_string(Utf16View);
|
||||
static StringView value_style_to_string(ValueStyle);
|
||||
static Utf16String value_style_to_string(ValueStyle);
|
||||
|
||||
static_assert(to_underlying(ValueStyle::Long) == to_underlying(Unicode::Style::Long));
|
||||
static_assert(to_underlying(ValueStyle::Short) == to_underlying(Unicode::Style::Short));
|
||||
|
|
@ -51,7 +51,7 @@ public:
|
|||
Always,
|
||||
};
|
||||
static Display display_from_string(Utf16View display);
|
||||
static StringView display_to_string(Display);
|
||||
static Utf16String display_to_string(Display);
|
||||
|
||||
enum class Unit {
|
||||
Years,
|
||||
|
|
@ -74,14 +74,14 @@ public:
|
|||
|
||||
virtual ~DurationFormat() override = default;
|
||||
|
||||
virtual ReadonlySpan<StringView> relevant_extension_keys() const override;
|
||||
virtual ReadonlySpan<Utf16View> relevant_extension_keys() const override;
|
||||
virtual ReadonlySpan<ResolutionOptionDescriptor> resolution_option_descriptors(VM&) const override;
|
||||
|
||||
void set_locale(String locale) { m_locale = move(locale); }
|
||||
String const& locale() const { return m_locale; }
|
||||
void set_locale(Utf16String locale) { m_locale = move(locale); }
|
||||
Utf16String const& locale() const { return m_locale; }
|
||||
|
||||
void set_numbering_system(String numbering_system) { m_numbering_system = move(numbering_system); }
|
||||
String const& numbering_system() const { return m_numbering_system; }
|
||||
void set_numbering_system(Utf16String numbering_system) { m_numbering_system = move(numbering_system); }
|
||||
Utf16String const& numbering_system() const { return m_numbering_system; }
|
||||
|
||||
void set_hour_minute_separator(Utf16String hour_minute_separator) { m_hour_minute_separator = move(hour_minute_separator); }
|
||||
Utf16String const& hour_minute_separator() const { return m_hour_minute_separator; }
|
||||
|
|
@ -91,7 +91,7 @@ public:
|
|||
|
||||
void set_style(Utf16View style) { m_style = style_from_string(style); }
|
||||
Style style() const { return m_style; }
|
||||
StringView style_string() const { return style_to_string(m_style); }
|
||||
Utf16String style_string() const { return style_to_string(m_style); }
|
||||
|
||||
void set_years_options(DurationUnitOptions years_options) { m_years_options = years_options; }
|
||||
DurationUnitOptions years_options() const { return m_years_options; }
|
||||
|
|
@ -130,8 +130,8 @@ public:
|
|||
private:
|
||||
explicit DurationFormat(Object& prototype);
|
||||
|
||||
String m_locale; // [[Locale]]
|
||||
String m_numbering_system; // [[NumberingSystem]]
|
||||
Utf16String m_locale; // [[Locale]]
|
||||
Utf16String m_numbering_system; // [[NumberingSystem]]
|
||||
Utf16String m_hour_minute_separator; // [[HourMinutesSeparator]]
|
||||
Utf16String m_minute_second_separator; // [[MinutesSecondsSeparator]]
|
||||
|
||||
|
|
@ -178,9 +178,9 @@ static constexpr auto duration_instances_components = to_array<DurationInstanceC
|
|||
});
|
||||
|
||||
struct DurationFormatPart {
|
||||
StringView type;
|
||||
Utf16String type;
|
||||
Utf16String value;
|
||||
Utf16View unit;
|
||||
Utf16String unit;
|
||||
};
|
||||
|
||||
ThrowCompletionOr<DurationFormat::DurationUnitOptions> get_duration_unit_options(VM&, DurationFormat::Unit unit, Object const& options, DurationFormat::Style base_style, ReadonlySpan<StringView> styles_list, DurationFormat::ValueStyle digital_base, Optional<DurationFormat::ValueStyle> previous_style, bool two_digit_hours);
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ ThrowCompletionOr<GC::Ref<Object>> DurationFormatConstructor::construct(Function
|
|||
// 7. Let resolvedLocaleData be r.[[LocaleData]].
|
||||
|
||||
// 8. Let digitalFormat be resolvedLocaleData.[[DigitalFormat]].
|
||||
auto digital_format = Unicode::digital_format(result.icu_locale);
|
||||
auto digital_format = Unicode::digital_format(result.icu_locale.utf16_view());
|
||||
|
||||
// 9. Set durationFormat.[[HourMinuteSeparator]] to digitalFormat.[[HourMinuteSeparator]].
|
||||
duration_format->set_hour_minute_separator(move(digital_format.hours_minutes_separator));
|
||||
|
|
@ -76,11 +76,11 @@ ThrowCompletionOr<GC::Ref<Object>> DurationFormatConstructor::construct(Function
|
|||
duration_format->set_minute_second_separator(move(digital_format.minutes_seconds_separator));
|
||||
|
||||
// 11. Set durationFormat.[[NumberingSystem]] to r.[[nu]].
|
||||
if (auto* resolved_numbering_system = result.nu.get_pointer<String>())
|
||||
if (auto* resolved_numbering_system = result.nu.get_pointer<Utf16String>())
|
||||
duration_format->set_numbering_system(move(*resolved_numbering_system));
|
||||
|
||||
// 12. Let style be ? GetOption(options, "style", STRING, « "long", "short", "narrow", "digital" », "short").
|
||||
auto style = TRY(get_option(vm, *options, vm.names.style, OptionType::String, { "long"sv, "short"sv, "narrow"sv, "digital"sv }, "short"sv));
|
||||
auto style = TRY(get_option(vm, *options, vm.names.style, OptionType::String, { "long"sv, "short"sv, "narrow"sv, "digital"sv }, u"short"sv));
|
||||
|
||||
// 13. Set durationFormat.[[Style]] to style.
|
||||
duration_format->set_style(style.as_string().utf16_string_view());
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ void DurationFormatPrototype::initialize(Realm& realm)
|
|||
auto& vm = this->vm();
|
||||
|
||||
// 13.3.5 Intl.DurationFormat.prototype [ %Symbol.toStringTag% ], https://tc39.es/ecma402/#sec-Intl.DurationFormat.prototype-%symbol.tostringtag%
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Intl.DurationFormat"_string), Attribute::Configurable);
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Intl.DurationFormat"_utf16_fly_string), Attribute::Configurable);
|
||||
|
||||
u8 attr = Attribute::Writable | Attribute::Configurable;
|
||||
define_native_function(realm, vm.names.resolvedOptions, resolved_options, 0, attr);
|
||||
|
|
@ -77,11 +77,13 @@ JS_DEFINE_NATIVE_FUNCTION(DurationFormatPrototype::resolved_options)
|
|||
}
|
||||
|
||||
// 5. Perform ! CreateDataPropertyOrThrow(options, p, style).
|
||||
MUST(options->create_data_property_or_throw(property, PrimitiveString::create(vm, DurationFormat::value_style_to_string(style))));
|
||||
auto style_string = DurationFormat::value_style_to_string(style);
|
||||
MUST(options->create_data_property_or_throw(property, PrimitiveString::create(vm, move(style_string))));
|
||||
|
||||
// 6. Set p to the string-concatenation of p and "Display".
|
||||
// 7. Set v to v.[[Display]].
|
||||
MUST(options->create_data_property_or_throw(*display_property, PrimitiveString::create(vm, DurationFormat::display_to_string(value.display))));
|
||||
auto display_string = DurationFormat::display_to_string(value.display);
|
||||
MUST(options->create_data_property_or_throw(*display_property, PrimitiveString::create(vm, move(display_string))));
|
||||
} else {
|
||||
// iv. Perform ! CreateDataPropertyOrThrow(options, p, v).
|
||||
MUST(options->create_data_property_or_throw(property, PrimitiveString::create(vm, move(value))));
|
||||
|
|
@ -162,14 +164,14 @@ JS_DEFINE_NATIVE_FUNCTION(DurationFormatPrototype::format_to_parts)
|
|||
auto object = Object::create(realm, realm.intrinsics().object_prototype());
|
||||
|
||||
// b. Perform ! CreateDataPropertyOrThrow(obj, "type", part.[[Type]]).
|
||||
MUST(object->create_data_property_or_throw(vm.names.type, PrimitiveString::create(vm, part.type)));
|
||||
MUST(object->create_data_property_or_throw(vm.names.type, PrimitiveString::create(vm, move(part.type))));
|
||||
|
||||
// c. Perform ! CreateDataPropertyOrThrow(obj, "value", part.[[Value]]).
|
||||
MUST(object->create_data_property_or_throw(vm.names.value, PrimitiveString::create(vm, move(part.value))));
|
||||
|
||||
// d. If part.[[Unit]] is not empty, perform ! CreateDataPropertyOrThrow(obj, "unit", part.[[Unit]]).
|
||||
if (!part.unit.is_empty())
|
||||
MUST(object->create_data_property_or_throw(vm.names.unit, PrimitiveString::create(vm, part.unit)));
|
||||
MUST(object->create_data_property_or_throw(vm.names.unit, PrimitiveString::create(vm, move(part.unit))));
|
||||
|
||||
// e. Perform ! CreateDataPropertyOrThrow(result, ! ToString(n), obj).
|
||||
MUST(result->create_data_property_or_throw(n, object));
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ void Intl::initialize(Realm& realm)
|
|||
auto& vm = this->vm();
|
||||
|
||||
// 8.1.1 Intl[ @@toStringTag ], https://tc39.es/ecma402/#sec-Intl-toStringTag
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Intl"_string), Attribute::Configurable);
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Intl"_utf16_fly_string), Attribute::Configurable);
|
||||
|
||||
u8 attr = Attribute::Writable | Attribute::Configurable;
|
||||
define_intrinsic_accessor(vm.names.Collator, attr, [](auto& realm) -> Value { return realm.intrinsics().intl_collator_constructor(); });
|
||||
|
|
@ -73,24 +73,20 @@ JS_DEFINE_NATIVE_FUNCTION(Intl::get_canonical_locales)
|
|||
// 1. Let ll be ? CanonicalizeLocaleList(locales).
|
||||
auto locale_list = TRY(canonicalize_locale_list(vm, locales));
|
||||
|
||||
GC::RootVector<Value> marked_locale_list;
|
||||
marked_locale_list.ensure_capacity(locale_list.size());
|
||||
|
||||
for (auto& locale : locale_list)
|
||||
marked_locale_list.unchecked_append(PrimitiveString::create(vm, move(locale)));
|
||||
|
||||
// 2. Return CreateArrayFromList(ll).
|
||||
return Array::create_from(realm, marked_locale_list);
|
||||
return Array::create_from<Utf16String>(realm, locale_list, [&vm](auto const& locale) {
|
||||
return PrimitiveString::create(vm, locale);
|
||||
});
|
||||
}
|
||||
|
||||
// 6.5.4 AvailablePrimaryTimeZoneIdentifiers ( ), https://tc39.es/ecma402/#sec-availableprimarytimezoneidentifiers
|
||||
static Vector<String> available_primary_time_zone_identifiers()
|
||||
static Vector<Utf16String> available_primary_time_zone_identifiers()
|
||||
{
|
||||
// 1. Let records be AvailableNamedTimeZoneIdentifiers().
|
||||
auto const& records = available_named_time_zone_identifiers();
|
||||
|
||||
// 2. Let result be a new empty List.
|
||||
Vector<String> result;
|
||||
Vector<Utf16String> result;
|
||||
|
||||
// 3. For each element timeZoneIdentifierRecord of records, do
|
||||
for (auto const& time_zone_identifier_record : records) {
|
||||
|
|
@ -113,7 +109,7 @@ JS_DEFINE_NATIVE_FUNCTION(Intl::supported_values_of)
|
|||
// 1. Let key be ? ToString(key).
|
||||
auto key = TRY(vm.argument(0).to_utf16_string(vm));
|
||||
|
||||
Optional<Variant<ReadonlySpan<StringView>, ReadonlySpan<String>>> list;
|
||||
Optional<ReadonlySpan<Utf16String>> list;
|
||||
|
||||
// 2. If key is "calendar", then
|
||||
if (key == "calendar"sv) {
|
||||
|
|
@ -138,13 +134,20 @@ JS_DEFINE_NATIVE_FUNCTION(Intl::supported_values_of)
|
|||
// 6. Else if key is "timeZone", then
|
||||
else if (key == "timeZone"sv) {
|
||||
// a. Let list be ! AvailablePrimaryTimeZoneIdentifiers( ).
|
||||
static NeverDestroyed<Vector<String>> time_zones { available_primary_time_zone_identifiers() };
|
||||
static NeverDestroyed<Vector<Utf16String>> time_zones { available_primary_time_zone_identifiers() };
|
||||
list = time_zones->span();
|
||||
}
|
||||
// 7. Else if key is "unit", then
|
||||
else if (key == "unit"sv) {
|
||||
// a. Let list be ! AvailableCanonicalUnits( ).
|
||||
static NeverDestroyed<Vector<StringView>> units { sanctioned_single_unit_identifiers() };
|
||||
static NeverDestroyed<Vector<Utf16String>> units { [] {
|
||||
Vector<Utf16String> units;
|
||||
auto sanctioned_units = sanctioned_single_unit_identifiers();
|
||||
units.ensure_capacity(sanctioned_units.size());
|
||||
for (auto unit : sanctioned_units)
|
||||
units.unchecked_append(Utf16String::from_utf16(unit));
|
||||
return units;
|
||||
}() };
|
||||
list = units->span();
|
||||
}
|
||||
// 8. Else,
|
||||
|
|
@ -154,11 +157,9 @@ JS_DEFINE_NATIVE_FUNCTION(Intl::supported_values_of)
|
|||
}
|
||||
|
||||
// 9. Return CreateArrayFromList( list ).
|
||||
return list->visit([&]<typename T>(ReadonlySpan<T> list) {
|
||||
return Array::create_from<T>(realm, list, [&](auto value) {
|
||||
return Array::create_from<Utf16String>(realm, *list, [&](auto const& value) {
|
||||
return PrimitiveString::create(vm, value);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <AK/Span.h>
|
||||
#include <AK/StringView.h>
|
||||
#include <AK/Utf16View.h>
|
||||
#include <LibJS/Runtime/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/Object.h>
|
||||
#include <LibJS/Runtime/PropertyKey.h>
|
||||
|
|
@ -16,7 +17,7 @@ namespace JS::Intl {
|
|||
|
||||
// https://tc39.es/ecma402/#resolution-option-descriptor
|
||||
struct ResolutionOptionDescriptor {
|
||||
StringView key;
|
||||
Utf16View key;
|
||||
PropertyKey property;
|
||||
OptionType type { OptionType::String };
|
||||
ReadonlySpan<StringView> values {};
|
||||
|
|
@ -26,7 +27,7 @@ class IntlObject : public Object {
|
|||
JS_OBJECT(IntlObject, Object);
|
||||
|
||||
public:
|
||||
virtual ReadonlySpan<StringView> relevant_extension_keys() const = 0;
|
||||
virtual ReadonlySpan<Utf16View> relevant_extension_keys() const = 0;
|
||||
virtual ReadonlySpan<ResolutionOptionDescriptor> resolution_option_descriptors(VM&) const = 0;
|
||||
|
||||
protected:
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ ListFormat::ListFormat(Object& prototype)
|
|||
}
|
||||
|
||||
// 14.2.3 Internal slots, https://tc39.es/ecma402/#sec-Intl.ListFormat-internal-slots
|
||||
ReadonlySpan<StringView> ListFormat::relevant_extension_keys() const
|
||||
ReadonlySpan<Utf16View> ListFormat::relevant_extension_keys() const
|
||||
{
|
||||
// The value of the [[RelevantExtensionKeys]] internal slot is « ».
|
||||
return {};
|
||||
|
|
@ -71,7 +71,7 @@ GC::Ref<Array> format_list_to_parts(VM& vm, ListFormat const& list_format, Reado
|
|||
auto object = Object::create(realm, realm.intrinsics().object_prototype());
|
||||
|
||||
// b. Perform ! CreateDataPropertyOrThrow(O, "type", part.[[Type]]).
|
||||
MUST(object->create_data_property_or_throw(vm.names.type, PrimitiveString::create(vm, part.type)));
|
||||
MUST(object->create_data_property_or_throw(vm.names.type, PrimitiveString::create(vm, move(part.type))));
|
||||
|
||||
// c. Perform ! CreateDataPropertyOrThrow(O, "value", part.[[Value]]).
|
||||
MUST(object->create_data_property_or_throw(vm.names.value, PrimitiveString::create(vm, move(part.value))));
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/String.h>
|
||||
#include <AK/StringView.h>
|
||||
#include <AK/Utf16String.h>
|
||||
#include <AK/Utf16View.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibJS/Runtime/Intl/IntlObject.h>
|
||||
|
|
@ -30,21 +30,19 @@ public:
|
|||
|
||||
virtual ~ListFormat() override = default;
|
||||
|
||||
virtual ReadonlySpan<StringView> relevant_extension_keys() const override;
|
||||
virtual ReadonlySpan<Utf16View> relevant_extension_keys() const override;
|
||||
virtual ReadonlySpan<ResolutionOptionDescriptor> resolution_option_descriptors(VM&) const override;
|
||||
|
||||
String const& locale() const { return m_locale; }
|
||||
void set_locale(String locale) { m_locale = move(locale); }
|
||||
Utf16String const& locale() const { return m_locale; }
|
||||
void set_locale(Utf16String locale) { m_locale = move(locale); }
|
||||
|
||||
Unicode::ListFormatType type() const { return m_type; }
|
||||
void set_type(StringView type) { m_type = Unicode::list_format_type_from_string(type); }
|
||||
void set_type(Utf16View type) { m_type = Unicode::list_format_type_from_string(type); }
|
||||
StringView type_string() const { return Unicode::list_format_type_to_string(m_type); }
|
||||
Utf16String type_string() const { return Unicode::list_format_type_to_string(m_type); }
|
||||
|
||||
Unicode::Style style() const { return m_style; }
|
||||
void set_style(StringView style) { m_style = Unicode::style_from_string(style); }
|
||||
void set_style(Utf16View style) { m_style = Unicode::style_from_string(style); }
|
||||
StringView style_string() const { return Unicode::style_to_string(m_style); }
|
||||
Utf16String style_string() const { return Unicode::style_to_string(m_style); }
|
||||
|
||||
Unicode::ListFormat const& formatter() const { return *m_formatter; }
|
||||
void set_formatter(NonnullOwnPtr<Unicode::ListFormat> formatter) { m_formatter = move(formatter); }
|
||||
|
|
@ -52,7 +50,7 @@ public:
|
|||
private:
|
||||
explicit ListFormat(Object& prototype);
|
||||
|
||||
String m_locale; // [[Locale]]
|
||||
Utf16String m_locale; // [[Locale]]
|
||||
Unicode::ListFormatType m_type { Unicode::ListFormatType::Conjunction }; // [[Type]]
|
||||
Unicode::Style m_style { Unicode::Style::Long }; // [[Style]]
|
||||
|
||||
|
|
|
|||
|
|
@ -63,13 +63,13 @@ ThrowCompletionOr<GC::Ref<Object>> ListFormatConstructor::construct(FunctionObje
|
|||
list_format->set_locale(move(result.locale));
|
||||
|
||||
// 7. Let type be ? GetOption(options, "type", string, « "conjunction", "disjunction", "unit" », "conjunction").
|
||||
auto type = TRY(get_option(vm, *options, vm.names.type, OptionType::String, { "conjunction"sv, "disjunction"sv, "unit"sv }, "conjunction"sv));
|
||||
auto type = TRY(get_option(vm, *options, vm.names.type, OptionType::String, { "conjunction"sv, "disjunction"sv, "unit"sv }, u"conjunction"sv));
|
||||
|
||||
// 8. Set listFormat.[[Type]] to type.
|
||||
list_format->set_type(type.as_string().utf16_string_view());
|
||||
|
||||
// 9. Let style be ? GetOption(options, "style", string, « "long", "short", "narrow" », "long").
|
||||
auto style = TRY(get_option(vm, *options, vm.names.style, OptionType::String, { "long"sv, "short"sv, "narrow"sv }, "long"sv));
|
||||
auto style = TRY(get_option(vm, *options, vm.names.style, OptionType::String, { "long"sv, "short"sv, "narrow"sv }, u"long"sv));
|
||||
|
||||
// 10. Set listFormat.[[Style]] to style.
|
||||
list_format->set_style(style.as_string().utf16_string_view());
|
||||
|
|
@ -78,7 +78,7 @@ ThrowCompletionOr<GC::Ref<Object>> ListFormatConstructor::construct(FunctionObje
|
|||
// 12. Let dataLocaleTypes be resolvedLocaleData.[[<type>]].
|
||||
// 13. Set listFormat.[[Templates]] to dataLocaleTypes.[[<style>]].
|
||||
auto formatter = Unicode::ListFormat::create(
|
||||
list_format->locale(),
|
||||
result.icu_locale.utf16_view().bytes(),
|
||||
list_format->type(),
|
||||
list_format->style());
|
||||
list_format->set_formatter(move(formatter));
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ void ListFormatPrototype::initialize(Realm& realm)
|
|||
auto& vm = this->vm();
|
||||
|
||||
// 14.3.5 Intl.ListFormat.prototype [ %Symbol.toStringTag% ], https://tc39.es/ecma402/#sec-Intl.ListFormat.prototype-toStringTag
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Intl.ListFormat"_string), Attribute::Configurable);
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Intl.ListFormat"_utf16_fly_string), Attribute::Configurable);
|
||||
|
||||
u8 attr = Attribute::Writable | Attribute::Configurable;
|
||||
define_native_function(realm, vm.names.resolvedOptions, resolved_options, 0, attr);
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ namespace JS::Intl {
|
|||
|
||||
GC_DEFINE_ALLOCATOR(Locale);
|
||||
|
||||
GC::Ref<Locale> Locale::create(Realm& realm, GC::Ref<Locale> source_locale, String locale_tag)
|
||||
GC::Ref<Locale> Locale::create(Realm& realm, GC::Ref<Locale> source_locale, Utf16String locale_tag)
|
||||
{
|
||||
auto locale = realm.create<Locale>(realm.intrinsics().intl_locale_prototype());
|
||||
|
||||
|
|
@ -38,11 +38,11 @@ Locale::Locale(Object& prototype)
|
|||
|
||||
Unicode::LocaleID const& Locale::locale_id() const
|
||||
{
|
||||
return m_cached_locale_id.ensure([&] { return Unicode::parse_unicode_locale_id(locale()); });
|
||||
return m_cached_locale_id.ensure([&] { return Unicode::parse_unicode_locale_id(locale().utf16_view()); });
|
||||
}
|
||||
|
||||
// 15.5.5 GetLocaleVariants ( locale ), https://tc39.es/ecma402/#sec-getlocalevariants
|
||||
Optional<String> get_locale_variants(Unicode::LocaleID const& locale)
|
||||
Optional<Utf16String> get_locale_variants(Unicode::LocaleID const& locale)
|
||||
{
|
||||
// 1. Let baseName be GetLocaleBaseName(locale).
|
||||
auto const& base_name = locale.language_id;
|
||||
|
|
@ -57,7 +57,7 @@ Optional<String> get_locale_variants(Unicode::LocaleID const& locale)
|
|||
return {};
|
||||
|
||||
// 4. Return the substring of variants from 1.
|
||||
return MUST(String::join("-"sv, base_name.variants));
|
||||
return Utf16String::join("-"sv, base_name.variants);
|
||||
}
|
||||
|
||||
// 15.5.9 CalendarsOfLocale ( loc ), https://tc39.es/ecma402/#sec-calendarsoflocale
|
||||
|
|
@ -82,10 +82,10 @@ GC::Ref<Array> calendars_of_locale(VM& vm, Locale const& locale_object)
|
|||
// in common use for date and time formatting in lookupRegion. The list is empty if no calendar preference data
|
||||
// for lookupRegion is available.
|
||||
// 8. If list is empty, set list to « "gregory" ».
|
||||
auto list = Unicode::available_calendars(locale_object.locale());
|
||||
auto list = Unicode::available_calendars(locale_object.locale().utf16_view());
|
||||
|
||||
// 9. Return CreateArrayFromList(list).
|
||||
return Array::create_from<String>(realm, list, [&vm](auto const& value) {
|
||||
return Array::create_from<Utf16String>(realm, list, [&vm](auto const& value) {
|
||||
return PrimitiveString::create(vm, value);
|
||||
});
|
||||
}
|
||||
|
|
@ -115,10 +115,10 @@ GC::Ref<Array> collations_of_locale(VM& vm, Locale const& locale_object)
|
|||
// 4. Else,
|
||||
// a. Let list be « "emoji", "eor" ».
|
||||
// 5. Let sorted be a copy of list, sorted according to lexicographic code unit order.
|
||||
auto list = Unicode::available_collations(locale_object.locale());
|
||||
auto list = Unicode::available_collations(locale_object.locale().utf16_view());
|
||||
|
||||
// 6. Return CreateArrayFromList(sorted).
|
||||
return Array::create_from<String>(realm, list, [&vm](auto const& value) {
|
||||
return Array::create_from<Utf16String>(realm, list, [&vm](auto const& value) {
|
||||
return PrimitiveString::create(vm, value);
|
||||
});
|
||||
}
|
||||
|
|
@ -143,10 +143,10 @@ GC::Ref<Array> hour_cycles_of_locale(VM& vm, Locale const& locale_object)
|
|||
// a. Let lookupRegion be region.
|
||||
// 7. Let list be a List of unique hour cycle identifiers, which must be lower case String values indicating either the 12-hour format ("h11", "h12") or the 24-hour format ("h23", "h24"), sorted in descending preference of those in common use for date and time formatting in lookupRegion. The list is empty if no time data for lookupRegion is available.
|
||||
// 8. If list is empty, set list to « "h23" ».
|
||||
auto list = Unicode::available_hour_cycles(locale_object.locale());
|
||||
auto list = Unicode::available_hour_cycles(locale_object.locale().utf16_view());
|
||||
|
||||
// 9. Return CreateArrayFromList(list).
|
||||
return Array::create_from<String>(realm, list, [&vm](auto const& value) {
|
||||
return Array::create_from<Utf16String>(realm, list, [&vm](auto const& value) {
|
||||
return PrimitiveString::create(vm, value);
|
||||
});
|
||||
}
|
||||
|
|
@ -170,10 +170,10 @@ GC::Ref<Array> numbering_systems_of_locale(VM& vm, Locale const& locale_object)
|
|||
// d. Let list be « numberingSystems[0] ».
|
||||
// 4. Else,
|
||||
// a. Let list be « "latn" ».
|
||||
auto list = Unicode::available_number_systems(locale_object.locale());
|
||||
auto list = Unicode::available_number_systems(locale_object.locale().utf16_view());
|
||||
|
||||
// 5. Return CreateArrayFromList(list).
|
||||
return Array::create_from<String>(realm, list, [&vm](auto const& value) {
|
||||
return Array::create_from<Utf16String>(realm, list, [&vm](auto const& value) {
|
||||
return PrimitiveString::create(vm, value);
|
||||
});
|
||||
}
|
||||
|
|
@ -193,16 +193,16 @@ Value time_zones_of_locale(VM& vm, Locale const& locale_object)
|
|||
// 3. Let list be a List of unique canonical time zone identifiers, which must be String values indicating a
|
||||
// canonical Zone name of the IANA Time Zone Database, of those in common use in region. The list is empty if no
|
||||
// time zones are commonly used in region. The list is sorted according to lexicographic code unit order.
|
||||
auto list = Unicode::available_time_zones_in_region(*region);
|
||||
auto list = Unicode::available_time_zones_in_region(region->utf16_view());
|
||||
|
||||
// 4. Return CreateArrayFromList( list ).
|
||||
return Array::create_from<String>(realm, list, [&vm](auto const& value) {
|
||||
return Array::create_from<Utf16String>(realm, list, [&vm](auto const& value) {
|
||||
return PrimitiveString::create(vm, value);
|
||||
});
|
||||
}
|
||||
|
||||
// 15.5.14 TextDirectionOfLocale ( loc ), https://tc39.es/ecma402/#sec-textdirectionoflocale
|
||||
StringView text_direction_of_locale(Locale const& locale_object)
|
||||
Utf16View text_direction_of_locale(Locale const& locale_object)
|
||||
{
|
||||
// 1. Let locale be loc.[[Locale]].
|
||||
auto const& locale = locale_object.locale();
|
||||
|
|
@ -218,29 +218,29 @@ StringView text_direction_of_locale(Locale const& locale_object)
|
|||
// 5. If the default general ordering of characters within a line in script is left-to-right, return "ltr".
|
||||
// 6. Return undefined.
|
||||
// FIXME: ICU does not provide a method to determine if a locale is neither rtl nor ltr.
|
||||
return Unicode::is_locale_character_ordering_right_to_left(locale) ? "rtl"sv : "ltr"sv;
|
||||
return Unicode::is_locale_character_ordering_right_to_left(locale.utf16_view()) ? Utf16View { "rtl"sv } : Utf16View { "ltr"sv };
|
||||
}
|
||||
|
||||
struct FirstDayStringAndValue {
|
||||
StringView weekday;
|
||||
StringView string;
|
||||
Utf16View weekday;
|
||||
Utf16View string;
|
||||
u8 value { 0 };
|
||||
};
|
||||
|
||||
// Table 26: Weekday String and Value, https://tc39.es/ecma402/#table-locale-weekday-string-value
|
||||
static constexpr auto WEEKDAY_STRING_AND_VALUE = to_array<FirstDayStringAndValue>({
|
||||
{ "0"sv, "sun"sv, 7 },
|
||||
{ "1"sv, "mon"sv, 1 },
|
||||
{ "2"sv, "tue"sv, 2 },
|
||||
{ "3"sv, "wed"sv, 3 },
|
||||
{ "4"sv, "thu"sv, 4 },
|
||||
{ "5"sv, "fri"sv, 5 },
|
||||
{ "6"sv, "sat"sv, 6 },
|
||||
{ "7"sv, "sun"sv, 7 },
|
||||
{ u"0"sv, u"sun"sv, 7 },
|
||||
{ u"1"sv, u"mon"sv, 1 },
|
||||
{ u"2"sv, u"tue"sv, 2 },
|
||||
{ u"3"sv, u"wed"sv, 3 },
|
||||
{ u"4"sv, u"thu"sv, 4 },
|
||||
{ u"5"sv, u"fri"sv, 5 },
|
||||
{ u"6"sv, u"sat"sv, 6 },
|
||||
{ u"7"sv, u"sun"sv, 7 },
|
||||
});
|
||||
|
||||
// 15.5.15 WeekdayToUValue ( fw ), https://tc39.es/ecma402/#sec-weekdaytouvalue
|
||||
StringView weekday_to_u_value(StringView weekday)
|
||||
Utf16View weekday_to_u_value(Utf16View weekday)
|
||||
{
|
||||
// 1. For each row of Table 26, except the header row, in table order, do
|
||||
for (auto const& row : WEEKDAY_STRING_AND_VALUE) {
|
||||
|
|
@ -256,7 +256,7 @@ StringView weekday_to_u_value(StringView weekday)
|
|||
}
|
||||
|
||||
// 15.5.16 WeekdayUValueToNumber ( fw ), https://tc39.es/ecma402/#sec-weekdayuvaluetonumber
|
||||
Optional<u8> weekday_u_value_to_number(StringView weekday)
|
||||
Optional<u8> weekday_u_value_to_number(Utf16View weekday)
|
||||
{
|
||||
// 1. For each row of Table 26, except the header row, in table order, do
|
||||
for (auto const& row : WEEKDAY_STRING_AND_VALUE) {
|
||||
|
|
@ -313,7 +313,7 @@ WeekInfo week_info_of_locale(Locale const& locale_object)
|
|||
auto const& locale = locale_object.locale();
|
||||
|
||||
// 2. Let r be a Record whose fields are defined by Table 27, with values based on locale.
|
||||
auto locale_week_info = Unicode::week_info_of_locale(locale);
|
||||
auto locale_week_info = Unicode::week_info_of_locale(locale.utf16_view());
|
||||
|
||||
WeekInfo week_info {};
|
||||
week_info.first_day = weekday_to_integer(locale_week_info.first_day_of_week, Unicode::Weekday::Monday);
|
||||
|
|
@ -326,7 +326,7 @@ WeekInfo week_info_of_locale(Locale const& locale_object)
|
|||
auto const& first_day_of_week_string = locale_object.first_day_of_week();
|
||||
|
||||
// 4. Let fw be WeekdayUValueToNumber(fws).
|
||||
first_day_of_week = weekday_u_value_to_number(first_day_of_week_string);
|
||||
first_day_of_week = weekday_u_value_to_number(first_day_of_week_string.utf16_view());
|
||||
}
|
||||
|
||||
// 5. If fw is not undefined, then
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <AK/Array.h>
|
||||
#include <AK/Optional.h>
|
||||
#include <AK/String.h>
|
||||
#include <AK/Utf16String.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibGC/Ptr.h>
|
||||
#include <LibJS/Runtime/Completion.h>
|
||||
|
|
@ -23,7 +24,7 @@ class Locale final : public Object {
|
|||
GC_DECLARE_ALLOCATOR(Locale);
|
||||
|
||||
public:
|
||||
static GC::Ref<Locale> create(Realm&, GC::Ref<Locale> source_locale, String);
|
||||
static GC::Ref<Locale> create(Realm&, GC::Ref<Locale> source_locale, Utf16String);
|
||||
|
||||
static constexpr auto locale_extension_keys()
|
||||
{
|
||||
|
|
@ -31,39 +32,39 @@ public:
|
|||
// The value of the [[LocaleExtensionKeys]] internal slot is a List that must include all elements of
|
||||
// « "ca", "co", "fw", "hc", "nu" », must additionally include any element of « "kf", "kn" » that is also an
|
||||
// element of %Intl.Collator%.[[RelevantExtensionKeys]], and must not include any other elements.
|
||||
return AK::Array { "ca"sv, "co"sv, "fw"sv, "hc"sv, "kf"sv, "kn"sv, "nu"sv };
|
||||
return AK::Array<Utf16View, 7> { "ca"sv, "co"sv, "fw"sv, "hc"sv, "kf"sv, "kn"sv, "nu"sv };
|
||||
}
|
||||
|
||||
virtual ~Locale() override = default;
|
||||
|
||||
Unicode::LocaleID const& locale_id() const;
|
||||
|
||||
String const& locale() const { return m_locale; }
|
||||
void set_locale(String locale) { m_locale = move(locale); }
|
||||
Utf16String const& locale() const { return m_locale; }
|
||||
void set_locale(Utf16String locale) { m_locale = move(locale); }
|
||||
|
||||
bool has_calendar() const { return m_calendar.has_value(); }
|
||||
String const& calendar() const { return m_calendar.value(); }
|
||||
void set_calendar(String calendar) { m_calendar = move(calendar); }
|
||||
Utf16String const& calendar() const { return m_calendar.value(); }
|
||||
void set_calendar(Utf16String calendar) { m_calendar = move(calendar); }
|
||||
|
||||
bool has_case_first() const { return m_case_first.has_value(); }
|
||||
String const& case_first() const { return m_case_first.value(); }
|
||||
void set_case_first(String case_first) { m_case_first = move(case_first); }
|
||||
Utf16String const& case_first() const { return m_case_first.value(); }
|
||||
void set_case_first(Utf16String case_first) { m_case_first = move(case_first); }
|
||||
|
||||
bool has_collation() const { return m_collation.has_value(); }
|
||||
String const& collation() const { return m_collation.value(); }
|
||||
void set_collation(String collation) { m_collation = move(collation); }
|
||||
Utf16String const& collation() const { return m_collation.value(); }
|
||||
void set_collation(Utf16String collation) { m_collation = move(collation); }
|
||||
|
||||
bool has_first_day_of_week() const { return m_first_day_of_week.has_value(); }
|
||||
String const& first_day_of_week() const { return m_first_day_of_week.value(); }
|
||||
void set_first_day_of_week(String first_day_of_week) { m_first_day_of_week = move(first_day_of_week); }
|
||||
Utf16String const& first_day_of_week() const { return m_first_day_of_week.value(); }
|
||||
void set_first_day_of_week(Utf16String first_day_of_week) { m_first_day_of_week = move(first_day_of_week); }
|
||||
|
||||
bool has_hour_cycle() const { return m_hour_cycle.has_value(); }
|
||||
String const& hour_cycle() const { return m_hour_cycle.value(); }
|
||||
void set_hour_cycle(String hour_cycle) { m_hour_cycle = move(hour_cycle); }
|
||||
Utf16String const& hour_cycle() const { return m_hour_cycle.value(); }
|
||||
void set_hour_cycle(Utf16String hour_cycle) { m_hour_cycle = move(hour_cycle); }
|
||||
|
||||
bool has_numbering_system() const { return m_numbering_system.has_value(); }
|
||||
String const& numbering_system() const { return m_numbering_system.value(); }
|
||||
void set_numbering_system(String numbering_system) { m_numbering_system = move(numbering_system); }
|
||||
Utf16String const& numbering_system() const { return m_numbering_system.value(); }
|
||||
void set_numbering_system(Utf16String numbering_system) { m_numbering_system = move(numbering_system); }
|
||||
|
||||
bool numeric() const { return m_numeric; }
|
||||
void set_numeric(bool numeric) { m_numeric = numeric; }
|
||||
|
|
@ -71,13 +72,13 @@ public:
|
|||
private:
|
||||
explicit Locale(Object& prototype);
|
||||
|
||||
String m_locale; // [[Locale]]
|
||||
Optional<String> m_calendar; // [[Calendar]]
|
||||
Optional<String> m_case_first; // [[CaseFirst]]
|
||||
Optional<String> m_collation; // [[Collation]]
|
||||
Optional<String> m_first_day_of_week; // [[FirstDayOfWeek]]
|
||||
Optional<String> m_hour_cycle; // [[HourCycle]]
|
||||
Optional<String> m_numbering_system; // [[NumberingSystem]]
|
||||
Utf16String m_locale; // [[Locale]]
|
||||
Optional<Utf16String> m_calendar; // [[Calendar]]
|
||||
Optional<Utf16String> m_case_first; // [[CaseFirst]]
|
||||
Optional<Utf16String> m_collation; // [[Collation]]
|
||||
Optional<Utf16String> m_first_day_of_week; // [[FirstDayOfWeek]]
|
||||
Optional<Utf16String> m_hour_cycle; // [[HourCycle]]
|
||||
Optional<Utf16String> m_numbering_system; // [[NumberingSystem]]
|
||||
bool m_numeric { false }; // [[Numeric]]
|
||||
|
||||
mutable Optional<Unicode::LocaleID> m_cached_locale_id;
|
||||
|
|
@ -89,16 +90,16 @@ struct WeekInfo {
|
|||
Vector<u8> weekend; // [[Weekend]]
|
||||
};
|
||||
|
||||
Optional<String> get_locale_variants(Unicode::LocaleID const&);
|
||||
Optional<Utf16String> get_locale_variants(Unicode::LocaleID const&);
|
||||
|
||||
GC::Ref<Array> calendars_of_locale(VM&, Locale const&);
|
||||
GC::Ref<Array> collations_of_locale(VM&, Locale const& locale);
|
||||
GC::Ref<Array> hour_cycles_of_locale(VM&, Locale const& locale);
|
||||
GC::Ref<Array> numbering_systems_of_locale(VM&, Locale const&);
|
||||
Value time_zones_of_locale(VM&, Locale const&);
|
||||
StringView text_direction_of_locale(Locale const&);
|
||||
StringView weekday_to_u_value(StringView weekday);
|
||||
Optional<u8> weekday_u_value_to_number(StringView weekday);
|
||||
Utf16View text_direction_of_locale(Locale const&);
|
||||
Utf16View weekday_to_u_value(Utf16View weekday);
|
||||
Optional<u8> weekday_u_value_to_number(Utf16View weekday);
|
||||
WeekInfo week_info_of_locale(Locale const&);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,14 +18,24 @@ namespace JS::Intl {
|
|||
GC_DEFINE_ALLOCATOR(LocaleConstructor);
|
||||
|
||||
struct LocaleAndKeys {
|
||||
String locale;
|
||||
Optional<String> ca;
|
||||
Optional<String> co;
|
||||
Optional<String> fw;
|
||||
Optional<String> hc;
|
||||
Optional<String> kf;
|
||||
Optional<String> kn;
|
||||
Optional<String> nu;
|
||||
Utf16String locale;
|
||||
Optional<Utf16String> ca;
|
||||
Optional<Utf16String> co;
|
||||
Optional<Utf16String> fw;
|
||||
Optional<Utf16String> hc;
|
||||
Optional<Utf16String> kf;
|
||||
Optional<Utf16String> kn;
|
||||
Optional<Utf16String> nu;
|
||||
};
|
||||
|
||||
struct LocaleOptionsAndKeys {
|
||||
Optional<Utf16String> ca;
|
||||
Optional<Utf16String> co;
|
||||
Optional<Utf16String> fw;
|
||||
Optional<Utf16String> hc;
|
||||
Optional<Utf16String> kf;
|
||||
Optional<Utf16String> kn;
|
||||
Optional<Utf16String> nu;
|
||||
};
|
||||
|
||||
static bool is_unicode_language_subtag(Utf16View subtag)
|
||||
|
|
@ -49,26 +59,24 @@ static bool is_type_identifier(Utf16View identifier)
|
|||
}
|
||||
|
||||
// NOTE: This is not an AO in the spec. This just serves to abstract very similar steps in UpdateLanguageId and the Intl.Locale constructor.
|
||||
static ThrowCompletionOr<Optional<String>> get_string_option(VM& vm, Object const& options, PropertyKey const& property, Function<bool(Utf16View)> validator, ReadonlySpan<StringView> values = {}, Optional<String> const& fallback = {})
|
||||
static ThrowCompletionOr<Optional<Utf16String>> get_string_option(VM& vm, Object const& options, PropertyKey const& property, Function<bool(Utf16View)> validator, ReadonlySpan<StringView> values = {}, Optional<Utf16String> const& fallback = {})
|
||||
{
|
||||
auto option_default = fallback.has_value() ? OptionDefault { *fallback } : Empty {};
|
||||
|
||||
auto option = TRY(get_option(vm, options, property, OptionType::String, values, option_default));
|
||||
auto option = TRY(get_option(vm, options, property, OptionType::String, values, Empty {}));
|
||||
if (option.is_undefined())
|
||||
return OptionalNone {};
|
||||
return fallback;
|
||||
|
||||
auto option_string = option.as_string().utf16_string_view();
|
||||
if (!option_string.is_ascii())
|
||||
auto option_string_view = option.as_string().utf16_string_view();
|
||||
if (!option_string_view.has_ascii_storage())
|
||||
return vm.throw_completion<RangeError>(ErrorType::OptionIsNotValidValue, option, property);
|
||||
|
||||
if (validator && !validator(option_string))
|
||||
if (validator && !validator(option_string_view))
|
||||
return vm.throw_completion<RangeError>(ErrorType::OptionIsNotValidValue, option, property);
|
||||
|
||||
return MUST(option_string.to_utf8());
|
||||
return Utf16String::from_utf16(option_string_view);
|
||||
}
|
||||
|
||||
// 15.1.2 UpdateLanguageId ( tag, options ), https://tc39.es/ecma402/#sec-updatelanguageid
|
||||
static ThrowCompletionOr<String> update_language_id(VM& vm, StringView tag, Object const& options)
|
||||
static ThrowCompletionOr<Utf16String> update_language_id(VM& vm, Utf16View tag, Object const& options)
|
||||
{
|
||||
auto locale_id = Unicode::parse_unicode_locale_id(tag);
|
||||
VERIFY(locale_id.has_value());
|
||||
|
|
@ -92,7 +100,7 @@ static ThrowCompletionOr<String> update_language_id(VM& vm, StringView tag, Obje
|
|||
|
||||
// 8. Let variants be ? GetOption(options, "variants", STRING, EMPTY, GetLocaleVariants(baseName)).
|
||||
auto variants = TRY(get_string_option(vm, options, vm.names.variants, nullptr, {}, get_locale_variants(*locale_id)));
|
||||
Vector<String> variant_subtags;
|
||||
Vector<Utf16String> variant_subtags;
|
||||
|
||||
// 9. If variants is not undefined, then
|
||||
if (variants.has_value()) {
|
||||
|
|
@ -104,9 +112,12 @@ static ThrowCompletionOr<String> update_language_id(VM& vm, StringView tag, Obje
|
|||
auto lower_variants = variants->to_ascii_lowercase();
|
||||
|
||||
// c. Let variantSubtags be StringSplitToList(lowerVariants, "-").
|
||||
variant_subtags = MUST(lower_variants.split('-', SplitBehavior::KeepEmpty));
|
||||
lower_variants.utf16_view().for_each_split_view('-', SplitBehavior::KeepEmpty, [&](auto variant) {
|
||||
variant_subtags.append(Utf16String::from_utf16(variant));
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
|
||||
HashTable<String> seen_variants;
|
||||
HashTable<Utf16String> seen_variants;
|
||||
bool has_duplicate_variant = false;
|
||||
|
||||
// d. For each element variant of variantSubtags, do
|
||||
|
|
@ -145,16 +156,16 @@ static ThrowCompletionOr<String> update_language_id(VM& vm, StringView tag, Obje
|
|||
new_tag.private_use_extensions = move(private_use_extensions);
|
||||
|
||||
// 16. Return newTag.
|
||||
return new_tag.to_string();
|
||||
return new_tag.to_utf16_string();
|
||||
}
|
||||
|
||||
// 15.1.3 MakeLocaleRecord ( tag, options, localeExtensionKeys ), https://tc39.es/ecma402/#sec-makelocalerecord
|
||||
static LocaleAndKeys make_locale_record(StringView tag, LocaleAndKeys options, ReadonlySpan<StringView> locale_extension_keys)
|
||||
static LocaleAndKeys make_locale_record(Utf16View tag, LocaleOptionsAndKeys options, ReadonlySpan<Utf16View> locale_extension_keys)
|
||||
{
|
||||
auto locale_id = Unicode::parse_unicode_locale_id(tag);
|
||||
VERIFY(locale_id.has_value());
|
||||
|
||||
Vector<String> attributes;
|
||||
Vector<Utf16String> attributes;
|
||||
Vector<Unicode::Keyword> keywords;
|
||||
|
||||
// 1. If tag contains a substring that is a Unicode locale extension sequence, then
|
||||
|
|
@ -174,7 +185,25 @@ static LocaleAndKeys make_locale_record(StringView tag, LocaleAndKeys options, R
|
|||
// a. Let attributes be a new empty List.
|
||||
// b. Let keywords be a new empty List.
|
||||
|
||||
auto field_from_key = [](LocaleAndKeys& value, StringView key) -> Optional<String>& {
|
||||
auto option_field_from_key = [](LocaleOptionsAndKeys& value, Utf16View key) -> Optional<Utf16String>& {
|
||||
if (key == "ca"sv)
|
||||
return value.ca;
|
||||
if (key == "co"sv)
|
||||
return value.co;
|
||||
if (key == "fw"sv)
|
||||
return value.fw;
|
||||
if (key == "hc"sv)
|
||||
return value.hc;
|
||||
if (key == "kf"sv)
|
||||
return value.kf;
|
||||
if (key == "kn"sv)
|
||||
return value.kn;
|
||||
if (key == "nu"sv)
|
||||
return value.nu;
|
||||
VERIFY_NOT_REACHED();
|
||||
};
|
||||
|
||||
auto result_field_from_key = [](LocaleAndKeys& value, Utf16View key) -> Optional<Utf16String>& {
|
||||
if (key == "ca"sv)
|
||||
return value.ca;
|
||||
if (key == "co"sv)
|
||||
|
|
@ -198,10 +227,10 @@ static LocaleAndKeys make_locale_record(StringView tag, LocaleAndKeys options, R
|
|||
// 4. For each element key of localeExtensionKeys, do
|
||||
for (auto const& key : locale_extension_keys) {
|
||||
Unicode::Keyword* entry = nullptr;
|
||||
Optional<String> value;
|
||||
Optional<Utf16String> value;
|
||||
|
||||
// a. If keywords contains an element whose [[Key]] is key, then
|
||||
if (auto it = keywords.find_if([&](auto const& k) { return key == k.key; }); it != keywords.end()) {
|
||||
if (auto it = keywords.find_if([&](auto const& k) { return k.key.utf16_view() == key; }); it != keywords.end()) {
|
||||
// i. Let entry be the element of keywords whose [[Key]] is key.
|
||||
entry = &(*it);
|
||||
|
||||
|
|
@ -214,12 +243,12 @@ static LocaleAndKeys make_locale_record(StringView tag, LocaleAndKeys options, R
|
|||
|
||||
// c. Assert: options has a field [[<key>]].
|
||||
// d. Let overrideValue be options.[[<key>]].
|
||||
auto const& override_value = field_from_key(options, key);
|
||||
auto const& override_value = option_field_from_key(options, key);
|
||||
|
||||
// e. If overrideValue is not undefined, then
|
||||
if (override_value.has_value()) {
|
||||
// i. Set value to CanonicalizeUValue(key, overrideValue).
|
||||
value = Unicode::canonicalize_unicode_extension_values(key, *override_value);
|
||||
value = Unicode::canonicalize_unicode_extension_values(key.bytes(), override_value->utf16_view());
|
||||
|
||||
// ii. If entry is not empty, then
|
||||
if (entry != nullptr) {
|
||||
|
|
@ -229,17 +258,18 @@ static LocaleAndKeys make_locale_record(StringView tag, LocaleAndKeys options, R
|
|||
// iii. Else,
|
||||
else {
|
||||
// 1. Append the Record { [[Key]]: key, [[Value]]: value } to keywords.
|
||||
keywords.empend(MUST(String::from_utf8(key)), *value);
|
||||
keywords.empend(Utf16String::from_utf16(key), *value);
|
||||
}
|
||||
}
|
||||
|
||||
// f. Set result.[[<key>]] to value.
|
||||
field_from_key(result, key) = move(value);
|
||||
if (value.has_value())
|
||||
result_field_from_key(result, key) = *value;
|
||||
}
|
||||
|
||||
// 5. Let locale be the String value that is tag with any Unicode locale extension sequences removed.
|
||||
locale_id->remove_extension_type<Unicode::LocaleExtension>();
|
||||
auto locale = locale_id->to_string();
|
||||
auto locale = locale_id->to_utf16_string();
|
||||
|
||||
// 6. If attributes is not empty or keywords is not empty, then
|
||||
if (!attributes.is_empty() || !keywords.is_empty()) {
|
||||
|
|
@ -303,7 +333,7 @@ ThrowCompletionOr<GC::Ref<Object>> LocaleConstructor::construct(FunctionObject&
|
|||
if (!tag_value.is_string() && !tag_value.is_object())
|
||||
return vm.throw_completion<TypeError>(ErrorType::NotAnObjectOrString, "tag"sv);
|
||||
|
||||
String tag;
|
||||
Utf16String tag;
|
||||
bool tag_is_canonicalized = false;
|
||||
|
||||
// 8. If tag is an Object and tag has an [[InitializedLocale]] internal slot, then
|
||||
|
|
@ -329,7 +359,7 @@ ThrowCompletionOr<GC::Ref<Object>> LocaleConstructor::construct(FunctionObject&
|
|||
auto options = TRY(coerce_options_to_object(vm, options_value));
|
||||
|
||||
// 11. If IsWellFormedLanguageTag(tag) is false, throw a RangeError exception.
|
||||
if (!tag_is_canonicalized && !is_well_formed_language_tag(tag))
|
||||
if (!tag_is_canonicalized && !is_well_formed_language_tag(tag.utf16_view()))
|
||||
return vm.throw_completion<RangeError>(ErrorType::IntlInvalidLanguageTag, tag);
|
||||
|
||||
// 12. NOTE: Because LanguageId canonicalization can alter tag in arbitrary ways according to Alias Rules from
|
||||
|
|
@ -337,14 +367,15 @@ ThrowCompletionOr<GC::Ref<Object>> LocaleConstructor::construct(FunctionObject&
|
|||
// options.
|
||||
|
||||
// 13. Set tag to CanonicalizeUnicodeLocaleId(tag).
|
||||
if (!tag_is_canonicalized)
|
||||
tag = canonicalize_unicode_locale_id(tag);
|
||||
if (!tag_is_canonicalized) {
|
||||
tag = canonicalize_unicode_locale_id(tag.utf16_view());
|
||||
}
|
||||
|
||||
// 14. Set tag to ? UpdateLanguageId(tag, options).
|
||||
tag = TRY(update_language_id(vm, tag, options));
|
||||
tag = TRY(update_language_id(vm, tag.utf16_view(), options));
|
||||
|
||||
// 15. Let opt be a new Record.
|
||||
LocaleAndKeys opt {};
|
||||
LocaleOptionsAndKeys opt {};
|
||||
|
||||
// 16. Let calendar be ? GetOption(options, "calendar", STRING, EMPTY, undefined).
|
||||
// 17. If calendar is not undefined, then
|
||||
|
|
@ -364,10 +395,10 @@ ThrowCompletionOr<GC::Ref<Object>> LocaleConstructor::construct(FunctionObject&
|
|||
// 23. If fw is not undefined, then
|
||||
if (first_day_of_week.has_value()) {
|
||||
// a. Set fw to WeekdayToUValue(fw).
|
||||
first_day_of_week = MUST(String::from_utf8(weekday_to_u_value(*first_day_of_week)));
|
||||
first_day_of_week = Utf16String::from_utf16(weekday_to_u_value(first_day_of_week->utf16_view()));
|
||||
|
||||
// b. If fw cannot be matched by the type Unicode locale nonterminal, throw a RangeError exception.
|
||||
if (!Unicode::is_type_identifier(*first_day_of_week))
|
||||
if (!Unicode::is_type_identifier(first_day_of_week->utf16_view()))
|
||||
return vm.throw_completion<RangeError>(ErrorType::OptionIsNotValidValue, *first_day_of_week, vm.names.firstDayOfWeek);
|
||||
}
|
||||
|
||||
|
|
@ -388,7 +419,7 @@ ThrowCompletionOr<GC::Ref<Object>> LocaleConstructor::construct(FunctionObject&
|
|||
// 30. If kn is not undefined, set kn to ! ToString(kn).
|
||||
// 31. Set opt.[[kn]] to kn.
|
||||
if (!kn.is_undefined())
|
||||
opt.kn = kn.as_bool() ? "true"_string : "false"_string;
|
||||
opt.kn = kn.as_bool() ? "true"_utf16 : "false"_utf16;
|
||||
|
||||
// 32. Let numberingSystem be ? GetOption(options, "numberingSystem", STRING, EMPTY, undefined).
|
||||
// 33. If numberingSystem is not undefined, then
|
||||
|
|
@ -397,7 +428,7 @@ ThrowCompletionOr<GC::Ref<Object>> LocaleConstructor::construct(FunctionObject&
|
|||
opt.nu = TRY(get_string_option(vm, options, vm.names.numberingSystem, is_type_identifier));
|
||||
|
||||
// 35. Let r be MakeLocaleRecord(tag, opt, localeExtensionKeys).
|
||||
auto result = make_locale_record(tag, move(opt), locale_extension_keys);
|
||||
auto result = make_locale_record(tag.utf16_view(), move(opt), locale_extension_keys);
|
||||
|
||||
// 36. Set locale.[[Locale]] to r.[[locale]].
|
||||
locale->set_locale(move(result.locale));
|
||||
|
|
@ -419,16 +450,16 @@ ThrowCompletionOr<GC::Ref<Object>> LocaleConstructor::construct(FunctionObject&
|
|||
locale->set_hour_cycle(result.hc.release_value());
|
||||
|
||||
// 41. If localeExtensionKeys contains "kf", then
|
||||
if (locale_extension_keys.span().contains_slow("kf"sv)) {
|
||||
if (locale_extension_keys.span().contains_slow(Utf16View { "kf"sv })) {
|
||||
// a. Set locale.[[CaseFirst]] to r.[[kf]].
|
||||
if (result.kf.has_value())
|
||||
locale->set_case_first(result.kf.release_value());
|
||||
}
|
||||
|
||||
// 42. If localeExtensionKeys contains "kn", then
|
||||
if (locale_extension_keys.span().contains_slow("kn"sv)) {
|
||||
if (locale_extension_keys.span().contains_slow(Utf16View { "kn"sv })) {
|
||||
// a. If SameValue(r.[[kn]], "true") is true or r.[[kn]] is the empty String, then
|
||||
if (result.kn.has_value() && (result.kn == "true"sv || result.kn->is_empty())) {
|
||||
if (result.kn.has_value() && (result.kn->utf16_view() == "true"sv || result.kn->is_empty())) {
|
||||
// i. Set locale.[[Numeric]] to true.
|
||||
locale->set_numeric(true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ void LocalePrototype::initialize(Realm& realm)
|
|||
define_native_function(realm, vm.names.getWeekInfo, get_week_info, 0, attr);
|
||||
|
||||
// 15.3.16 Intl.Locale.prototype [ %Symbol.toStringTag% ], https://tc39.es/ecma402/#sec-intl.locale.prototype-%symbol.tostringtag%
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Intl.Locale"_string), Attribute::Configurable);
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Intl.Locale"_utf16_fly_string), Attribute::Configurable);
|
||||
|
||||
define_native_accessor(realm, vm.names.baseName, base_name, {}, Attribute::Configurable);
|
||||
define_native_accessor(realm, vm.names.calendar, calendar, {}, Attribute::Configurable);
|
||||
|
|
@ -64,7 +64,7 @@ JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::base_name)
|
|||
auto locale_object = TRY(typed_this_object(vm));
|
||||
|
||||
// 3. Return GetLocaleBaseName(loc.[[Locale]]).
|
||||
return PrimitiveString::create(vm, locale_object->locale_id().language_id.to_string());
|
||||
return PrimitiveString::create(vm, locale_object->locale_id().language_id.to_utf16_string());
|
||||
}
|
||||
|
||||
#define JS_ENUMERATE_LOCALE_KEYWORD_PROPERTIES \
|
||||
|
|
@ -113,7 +113,9 @@ JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::maximize)
|
|||
auto locale_object = TRY(typed_this_object(vm));
|
||||
|
||||
// 3. Let maximal be the result of the Add Likely Subtags algorithm applied to loc.[[Locale]]. If an error is signaled, set maximal to loc.[[Locale]].
|
||||
auto maximal = Unicode::add_likely_subtags(locale_object->locale()).value_or(locale_object->locale());
|
||||
auto maximal = locale_object->locale();
|
||||
if (auto maximal_locale = Unicode::add_likely_subtags(locale_object->locale().utf16_view().bytes()); maximal_locale.has_value())
|
||||
maximal = maximal_locale.release_value();
|
||||
|
||||
// 4. Return ! Construct(%Intl.Locale%, maximal).
|
||||
return Locale::create(realm, locale_object, move(maximal));
|
||||
|
|
@ -129,7 +131,9 @@ JS_DEFINE_NATIVE_FUNCTION(LocalePrototype::minimize)
|
|||
auto locale_object = TRY(typed_this_object(vm));
|
||||
|
||||
// 3. Let minimal be the result of the Remove Likely Subtags algorithm applied to loc.[[Locale]]. If an error is signaled, set minimal to loc.[[Locale]].
|
||||
auto minimal = Unicode::remove_likely_subtags(locale_object->locale()).value_or(locale_object->locale());
|
||||
auto minimal = locale_object->locale();
|
||||
if (auto minimal_locale = Unicode::remove_likely_subtags(locale_object->locale().utf16_view().bytes()); minimal_locale.has_value())
|
||||
minimal = minimal_locale.release_value();
|
||||
|
||||
// 4. Return ! Construct(%Intl.Locale%, minimal).
|
||||
return Locale::create(realm, locale_object, move(minimal));
|
||||
|
|
|
|||
|
|
@ -8,6 +8,16 @@
|
|||
|
||||
namespace JS::Intl {
|
||||
|
||||
MathematicalValue::MathematicalValue(Value value)
|
||||
{
|
||||
if (value.is_number()) {
|
||||
m_value = value_from_number(value.as_double());
|
||||
return;
|
||||
}
|
||||
|
||||
m_value = MUST(value.as_bigint().big_integer().to_base_utf16(10));
|
||||
}
|
||||
|
||||
bool MathematicalValue::is_number() const
|
||||
{
|
||||
return m_value.has<double>();
|
||||
|
|
|
|||
|
|
@ -44,12 +44,7 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
MathematicalValue(Value value)
|
||||
: m_value(value.is_number()
|
||||
? value_from_number(value.as_double())
|
||||
: ValueType(Utf16String::from_utf8(MUST(value.as_bigint().big_integer().to_base(10)))))
|
||||
{
|
||||
}
|
||||
MathematicalValue(Value);
|
||||
|
||||
bool is_number() const;
|
||||
double as_number() const;
|
||||
|
|
|
|||
|
|
@ -39,10 +39,10 @@ void NumberFormat::visit_edges(Cell::Visitor& visitor)
|
|||
}
|
||||
|
||||
// 16.2.3 Internal slots, https://tc39.es/ecma402/#sec-intl.numberformat-internal-slots
|
||||
ReadonlySpan<StringView> NumberFormat::relevant_extension_keys() const
|
||||
ReadonlySpan<Utf16View> NumberFormat::relevant_extension_keys() const
|
||||
{
|
||||
// The value of the [[RelevantExtensionKeys]] internal slot is « "nu" ».
|
||||
static constexpr AK::Array keys { "nu"sv };
|
||||
static constexpr AK::Array<Utf16View, 1> keys { "nu"sv };
|
||||
return keys;
|
||||
}
|
||||
|
||||
|
|
@ -60,15 +60,15 @@ ReadonlySpan<ResolutionOptionDescriptor> NumberFormat::resolution_option_descrip
|
|||
return *descriptors;
|
||||
}
|
||||
|
||||
StringView NumberFormatBase::computed_rounding_priority_string() const
|
||||
Utf16String NumberFormatBase::computed_rounding_priority_string() const
|
||||
{
|
||||
switch (m_computed_rounding_priority) {
|
||||
case ComputedRoundingPriority::Auto:
|
||||
return "auto"sv;
|
||||
return "auto"_utf16;
|
||||
case ComputedRoundingPriority::MorePrecision:
|
||||
return "morePrecision"sv;
|
||||
return "morePrecision"_utf16;
|
||||
case ComputedRoundingPriority::LessPrecision:
|
||||
return "lessPrecision"sv;
|
||||
return "lessPrecision"_utf16;
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
|
@ -79,8 +79,9 @@ Value NumberFormat::use_grouping_to_value(VM& vm) const
|
|||
switch (m_use_grouping) {
|
||||
case Unicode::Grouping::Always:
|
||||
case Unicode::Grouping::Auto:
|
||||
case Unicode::Grouping::Min2:
|
||||
case Unicode::Grouping::Min2: {
|
||||
return PrimitiveString::create(vm, Unicode::grouping_to_string(m_use_grouping));
|
||||
}
|
||||
case Unicode::Grouping::False:
|
||||
return Value(false);
|
||||
default:
|
||||
|
|
@ -140,11 +141,11 @@ Unicode::DisplayOptions NumberFormat::display_options() const
|
|||
}
|
||||
|
||||
// 16.5.1 CurrencyDigits ( currency ), https://tc39.es/ecma402/#sec-currencydigits
|
||||
int currency_digits(StringView currency)
|
||||
int currency_digits(Utf16View currency)
|
||||
{
|
||||
// 1. If the ISO 4217 currency and funds code list contains currency as an alphabetic code, return the minor
|
||||
// unit value corresponding to the currency from the list; otherwise, return 2.
|
||||
if (auto currency_code = Unicode::get_currency_code(currency); currency_code.has_value())
|
||||
if (auto currency_code = Unicode::get_currency_code(currency.bytes()); currency_code.has_value())
|
||||
return currency_code->minor_unit.value_or(2);
|
||||
return 2;
|
||||
}
|
||||
|
|
@ -186,7 +187,7 @@ GC::Ref<Array> format_numeric_to_parts(VM& vm, NumberFormat const& number_format
|
|||
auto object = Object::create(realm, realm.intrinsics().object_prototype());
|
||||
|
||||
// b. Perform ! CreateDataPropertyOrThrow(O, "type", part.[[Type]]).
|
||||
MUST(object->create_data_property_or_throw(vm.names.type, PrimitiveString::create(vm, part.type)));
|
||||
MUST(object->create_data_property_or_throw(vm.names.type, PrimitiveString::create(vm, move(part.type))));
|
||||
|
||||
// c. Perform ! CreateDataPropertyOrThrow(O, "value", part.[[Value]]).
|
||||
MUST(object->create_data_property_or_throw(vm.names.value, PrimitiveString::create(vm, move(part.value))));
|
||||
|
|
@ -210,7 +211,7 @@ ThrowCompletionOr<MathematicalValue> to_intl_mathematical_value(VM& vm, Value va
|
|||
|
||||
// 2. If Type(primValue) is BigInt, return the mathematical value of primValue.
|
||||
if (primitive_value.is_bigint())
|
||||
return Utf16String::from_utf8(MUST(value.as_bigint().big_integer().to_base(10)));
|
||||
return MUST(value.as_bigint().big_integer().to_base_utf16(10));
|
||||
|
||||
// FIXME: The remaining steps are being refactored into a new Runtime Semantic, StringIntlMV.
|
||||
// We short-circuit some of these steps to avoid known pitfalls.
|
||||
|
|
@ -303,13 +304,13 @@ ThrowCompletionOr<GC::Ref<Array>> format_numeric_range_to_parts(VM& vm, NumberFo
|
|||
auto object = Object::create(realm, realm.intrinsics().object_prototype());
|
||||
|
||||
// b. Perform ! CreateDataPropertyOrThrow(O, "type", part.[[Type]]).
|
||||
MUST(object->create_data_property_or_throw(vm.names.type, PrimitiveString::create(vm, part.type)));
|
||||
MUST(object->create_data_property_or_throw(vm.names.type, PrimitiveString::create(vm, move(part.type))));
|
||||
|
||||
// c. Perform ! CreateDataPropertyOrThrow(O, "value", part.[[Value]]).
|
||||
MUST(object->create_data_property_or_throw(vm.names.value, PrimitiveString::create(vm, move(part.value))));
|
||||
|
||||
// d. Perform ! CreateDataPropertyOrThrow(O, "source", part.[[Source]]).
|
||||
MUST(object->create_data_property_or_throw(vm.names.source, PrimitiveString::create(vm, part.source)));
|
||||
MUST(object->create_data_property_or_throw(vm.names.source, PrimitiveString::create(vm, move(part.source))));
|
||||
|
||||
// e. Perform ! CreateDataPropertyOrThrow(result, ! ToString(n), O).
|
||||
MUST(result->create_data_property_or_throw(n, object));
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <AK/Optional.h>
|
||||
#include <AK/String.h>
|
||||
#include <AK/Utf16String.h>
|
||||
#include <AK/Utf16View.h>
|
||||
#include <LibJS/Export.h>
|
||||
#include <LibJS/Runtime/Intl/AbstractOperations.h>
|
||||
|
|
@ -32,8 +33,8 @@ public:
|
|||
|
||||
virtual ~NumberFormatBase() override = default;
|
||||
|
||||
String const& locale() const { return m_locale; }
|
||||
void set_locale(String locale) { m_locale = move(locale); }
|
||||
Utf16String const& locale() const { return m_locale; }
|
||||
void set_locale(Utf16String locale) { m_locale = move(locale); }
|
||||
|
||||
int min_integer_digits() const { return m_min_integer_digits; }
|
||||
void set_min_integer_digits(int min_integer_digits) { m_min_integer_digits = min_integer_digits; }
|
||||
|
|
@ -55,35 +56,31 @@ public:
|
|||
void set_max_significant_digits(int max_significant_digits) { m_max_significant_digits = max_significant_digits; }
|
||||
|
||||
Unicode::Notation notation() const { return m_notation; }
|
||||
StringView notation_string() const { return Unicode::notation_to_string(m_notation); }
|
||||
void set_notation(StringView notation) { m_notation = Unicode::notation_from_string(notation); }
|
||||
Utf16String notation_string() const { return Unicode::notation_to_string(m_notation); }
|
||||
void set_notation(Utf16View notation) { m_notation = Unicode::notation_from_string(notation); }
|
||||
|
||||
bool has_compact_display() const { return m_compact_display.has_value(); }
|
||||
Unicode::CompactDisplay compact_display() const { return *m_compact_display; }
|
||||
StringView compact_display_string() const { return Unicode::compact_display_to_string(*m_compact_display); }
|
||||
void set_compact_display(StringView compact_display) { m_compact_display = Unicode::compact_display_from_string(compact_display); }
|
||||
Utf16String compact_display_string() const { return Unicode::compact_display_to_string(*m_compact_display); }
|
||||
void set_compact_display(Utf16View compact_display) { m_compact_display = Unicode::compact_display_from_string(compact_display); }
|
||||
|
||||
Unicode::RoundingType rounding_type() const { return m_rounding_type; }
|
||||
StringView rounding_type_string() const { return Unicode::rounding_type_to_string(m_rounding_type); }
|
||||
Utf16String rounding_type_string() const { return Unicode::rounding_type_to_string(m_rounding_type); }
|
||||
void set_rounding_type(Unicode::RoundingType rounding_type) { m_rounding_type = rounding_type; }
|
||||
|
||||
ComputedRoundingPriority computed_rounding_priority() const { return m_computed_rounding_priority; }
|
||||
StringView computed_rounding_priority_string() const;
|
||||
Utf16String computed_rounding_priority_string() const;
|
||||
void set_computed_rounding_priority(ComputedRoundingPriority computed_rounding_priority) { m_computed_rounding_priority = computed_rounding_priority; }
|
||||
|
||||
Unicode::RoundingMode rounding_mode() const { return m_rounding_mode; }
|
||||
StringView rounding_mode_string() const { return Unicode::rounding_mode_to_string(m_rounding_mode); }
|
||||
void set_rounding_mode(StringView rounding_mode) { m_rounding_mode = Unicode::rounding_mode_from_string(rounding_mode); }
|
||||
Utf16String rounding_mode_string() const { return Unicode::rounding_mode_to_string(m_rounding_mode); }
|
||||
void set_rounding_mode(Utf16View rounding_mode) { m_rounding_mode = Unicode::rounding_mode_from_string(rounding_mode); }
|
||||
|
||||
int rounding_increment() const { return m_rounding_increment; }
|
||||
void set_rounding_increment(int rounding_increment) { m_rounding_increment = rounding_increment; }
|
||||
|
||||
Unicode::TrailingZeroDisplay trailing_zero_display() const { return m_trailing_zero_display; }
|
||||
StringView trailing_zero_display_string() const { return Unicode::trailing_zero_display_to_string(m_trailing_zero_display); }
|
||||
void set_trailing_zero_display(StringView trailing_zero_display) { m_trailing_zero_display = Unicode::trailing_zero_display_from_string(trailing_zero_display); }
|
||||
Utf16String trailing_zero_display_string() const { return Unicode::trailing_zero_display_to_string(m_trailing_zero_display); }
|
||||
void set_trailing_zero_display(Utf16View trailing_zero_display) { m_trailing_zero_display = Unicode::trailing_zero_display_from_string(trailing_zero_display); }
|
||||
|
||||
virtual Unicode::DisplayOptions display_options() const;
|
||||
|
|
@ -96,7 +93,7 @@ protected:
|
|||
explicit NumberFormatBase(Object& prototype);
|
||||
|
||||
private:
|
||||
String m_locale; // [[Locale]]
|
||||
Utf16String m_locale; // [[Locale]]
|
||||
int m_min_integer_digits { 0 }; // [[MinimumIntegerDigits]]
|
||||
Optional<int> m_min_fraction_digits {}; // [[MinimumFractionDigits]]
|
||||
Optional<int> m_max_fraction_digits {}; // [[MaximumFractionDigits]]
|
||||
|
|
@ -121,41 +118,37 @@ class NumberFormat final : public NumberFormatBase {
|
|||
public:
|
||||
virtual ~NumberFormat() override = default;
|
||||
|
||||
virtual ReadonlySpan<StringView> relevant_extension_keys() const override;
|
||||
virtual ReadonlySpan<Utf16View> relevant_extension_keys() const override;
|
||||
virtual ReadonlySpan<ResolutionOptionDescriptor> resolution_option_descriptors(VM&) const override;
|
||||
|
||||
String const& numbering_system() const { return m_numbering_system; }
|
||||
void set_numbering_system(String numbering_system) { m_numbering_system = move(numbering_system); }
|
||||
Utf16String const& numbering_system() const { return m_numbering_system; }
|
||||
void set_numbering_system(Utf16String numbering_system) { m_numbering_system = move(numbering_system); }
|
||||
|
||||
Unicode::NumberFormatStyle style() const { return m_style; }
|
||||
StringView style_string() const { return Unicode::number_format_style_to_string(m_style); }
|
||||
void set_style(StringView style) { m_style = Unicode::number_format_style_from_string(style); }
|
||||
Utf16String style_string() const { return Unicode::number_format_style_to_string(m_style); }
|
||||
void set_style(Utf16View style) { m_style = Unicode::number_format_style_from_string(style); }
|
||||
|
||||
bool has_currency() const { return m_currency.has_value(); }
|
||||
String const& currency() const { return m_currency.value(); }
|
||||
void set_currency(String currency) { m_currency = move(currency); }
|
||||
Utf16String const& currency() const { return m_currency.value(); }
|
||||
void set_currency(Utf16String currency) { m_currency = move(currency); }
|
||||
|
||||
bool has_currency_display() const { return m_currency_display.has_value(); }
|
||||
Unicode::CurrencyDisplay currency_display() const { return *m_currency_display; }
|
||||
StringView currency_display_string() const { return Unicode::currency_display_to_string(*m_currency_display); }
|
||||
void set_currency_display(StringView currency_display) { m_currency_display = Unicode::currency_display_from_string(currency_display); }
|
||||
Utf16String currency_display_string() const { return Unicode::currency_display_to_string(*m_currency_display); }
|
||||
void set_currency_display(Utf16View currency_display) { m_currency_display = Unicode::currency_display_from_string(currency_display); }
|
||||
|
||||
bool has_currency_sign() const { return m_currency_sign.has_value(); }
|
||||
Unicode::CurrencySign currency_sign() const { return *m_currency_sign; }
|
||||
StringView currency_sign_string() const { return Unicode::currency_sign_to_string(*m_currency_sign); }
|
||||
void set_currency_sign(StringView currency_sign) { m_currency_sign = Unicode::currency_sign_from_string(currency_sign); }
|
||||
Utf16String currency_sign_string() const { return Unicode::currency_sign_to_string(*m_currency_sign); }
|
||||
void set_currency_sign(Utf16View currency_sign) { m_currency_sign = Unicode::currency_sign_from_string(currency_sign); }
|
||||
|
||||
bool has_unit() const { return m_unit.has_value(); }
|
||||
String const& unit() const { return m_unit.value(); }
|
||||
void set_unit(String unit) { m_unit = move(unit); }
|
||||
Utf16String const& unit() const { return m_unit.value(); }
|
||||
void set_unit(Utf16String unit) { m_unit = move(unit); }
|
||||
|
||||
bool has_unit_display() const { return m_unit_display.has_value(); }
|
||||
Unicode::Style unit_display() const { return *m_unit_display; }
|
||||
StringView unit_display_string() const { return Unicode::style_to_string(*m_unit_display); }
|
||||
void set_unit_display(StringView unit_display) { m_unit_display = Unicode::style_from_string(unit_display); }
|
||||
Utf16String unit_display_string() const { return Unicode::style_to_string(*m_unit_display); }
|
||||
void set_unit_display(Utf16View unit_display) { m_unit_display = Unicode::style_from_string(unit_display); }
|
||||
|
||||
Unicode::Grouping use_grouping() const { return m_use_grouping; }
|
||||
|
|
@ -163,8 +156,7 @@ public:
|
|||
void set_use_grouping(StringOrBoolean const& use_grouping);
|
||||
|
||||
Unicode::SignDisplay sign_display() const { return m_sign_display; }
|
||||
StringView sign_display_string() const { return Unicode::sign_display_to_string(m_sign_display); }
|
||||
void set_sign_display(StringView sign_display) { m_sign_display = Unicode::sign_display_from_string(sign_display); }
|
||||
Utf16String sign_display_string() const { return Unicode::sign_display_to_string(m_sign_display); }
|
||||
void set_sign_display(Utf16View sign_display) { m_sign_display = Unicode::sign_display_from_string(sign_display); }
|
||||
|
||||
NativeFunction* bound_format() const { return m_bound_format; }
|
||||
|
|
@ -177,20 +169,19 @@ private:
|
|||
|
||||
virtual void visit_edges(Visitor&) override;
|
||||
|
||||
String m_locale; // [[Locale]]
|
||||
String m_numbering_system; // [[NumberingSystem]]
|
||||
Utf16String m_numbering_system; // [[NumberingSystem]]
|
||||
Unicode::NumberFormatStyle m_style; // [[Style]]
|
||||
Optional<String> m_currency; // [[Currency]]
|
||||
Optional<Utf16String> m_currency; // [[Currency]]
|
||||
Optional<Unicode::CurrencyDisplay> m_currency_display; // [[CurrencyDisplay]]
|
||||
Optional<Unicode::CurrencySign> m_currency_sign; // [[CurrencySign]]
|
||||
Optional<String> m_unit; // [[Unit]]
|
||||
Optional<Utf16String> m_unit; // [[Unit]]
|
||||
Optional<Unicode::Style> m_unit_display; // [[UnitDisplay]]
|
||||
Unicode::Grouping m_use_grouping { Unicode::Grouping::False }; // [[UseGrouping]]
|
||||
Unicode::SignDisplay m_sign_display; // [[SignDisplay]]
|
||||
GC::Ptr<NativeFunction> m_bound_format; // [[BoundFormat]]
|
||||
};
|
||||
|
||||
int currency_digits(StringView currency);
|
||||
int currency_digits(Utf16View currency);
|
||||
Vector<Unicode::NumberFormat::Partition> partition_number_pattern(NumberFormat const&, MathematicalValue const& number);
|
||||
Utf16String format_numeric(NumberFormat const&, MathematicalValue const& number);
|
||||
GC::Ref<Array> format_numeric_to_parts(VM&, NumberFormat const&, MathematicalValue const& number);
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ namespace JS::Intl {
|
|||
|
||||
GC_DEFINE_ALLOCATOR(NumberFormatConstructor);
|
||||
|
||||
static String ascii_uppercase_currency_code(Utf16View currency)
|
||||
static Utf16String ascii_uppercase_currency_code(Utf16View currency)
|
||||
{
|
||||
VERIFY(currency.length_in_code_units() == 3);
|
||||
|
||||
|
|
@ -26,7 +26,7 @@ static String ascii_uppercase_currency_code(Utf16View currency)
|
|||
code[i] = static_cast<char>(to_ascii_uppercase(currency.code_unit_at(i)));
|
||||
}
|
||||
|
||||
return String::from_ascii_short_string_without_validation(code, 3);
|
||||
return Utf16String::from_ascii_without_validation({ code, 3 });
|
||||
}
|
||||
|
||||
// 16.1 The Intl.NumberFormat Constructor, https://tc39.es/ecma402/#sec-intl-numberformat-constructor
|
||||
|
|
@ -79,7 +79,7 @@ ThrowCompletionOr<GC::Ref<Object>> NumberFormatConstructor::construct(FunctionOb
|
|||
// 7. Set numberFormat.[[LocaleData]] to r.[[LocaleData]].
|
||||
|
||||
// 8. Set numberFormat.[[NumberingSystem]] to r.[[nu]].
|
||||
if (auto* resolved_numbering_system = result.nu.get_pointer<String>())
|
||||
if (auto* resolved_numbering_system = result.nu.get_pointer<Utf16String>())
|
||||
number_format->set_numbering_system(move(*resolved_numbering_system));
|
||||
|
||||
// 9. Perform ? SetNumberFormatUnitOptions(numberFormat, options).
|
||||
|
|
@ -89,7 +89,7 @@ ThrowCompletionOr<GC::Ref<Object>> NumberFormatConstructor::construct(FunctionOb
|
|||
auto style = number_format->style();
|
||||
|
||||
// 11. Let notation be ? GetOption(options, "notation", STRING, « "standard", "scientific", "engineering", "compact" », "standard").
|
||||
auto notation = TRY(get_option(vm, *options, vm.names.notation, OptionType::String, { "standard"sv, "scientific"sv, "engineering"sv, "compact"sv }, "standard"sv));
|
||||
auto notation = TRY(get_option(vm, *options, vm.names.notation, OptionType::String, { "standard"sv, "scientific"sv, "engineering"sv, "compact"sv }, u"standard"sv));
|
||||
|
||||
// 12. Set numberFormat.[[Notation]] to notation.
|
||||
number_format->set_notation(notation.as_string().utf16_string_view());
|
||||
|
|
@ -127,7 +127,7 @@ ThrowCompletionOr<GC::Ref<Object>> NumberFormatConstructor::construct(FunctionOb
|
|||
TRY(set_number_format_digit_options(vm, number_format, *options, default_min_fraction_digits, default_max_fraction_digits, number_format->notation()));
|
||||
|
||||
// 16. Let compactDisplay be ? GetOption(options, "compactDisplay", STRING, « "short", "long" », "short").
|
||||
auto compact_display = TRY(get_option(vm, *options, vm.names.compactDisplay, OptionType::String, { "short"sv, "long"sv }, "short"sv));
|
||||
auto compact_display = TRY(get_option(vm, *options, vm.names.compactDisplay, OptionType::String, { "short"sv, "long"sv }, u"short"sv));
|
||||
|
||||
// 17. Let defaultUseGrouping be "auto".
|
||||
auto default_use_grouping = "auto"sv;
|
||||
|
|
@ -161,7 +161,7 @@ ThrowCompletionOr<GC::Ref<Object>> NumberFormatConstructor::construct(FunctionOb
|
|||
number_format->set_use_grouping(use_grouping);
|
||||
|
||||
// 24. Let signDisplay be ? GetOption(options, "signDisplay", STRING, « "auto", "never", "always", "exceptZero", "negative" », "auto").
|
||||
auto sign_display = TRY(get_option(vm, *options, vm.names.signDisplay, OptionType::String, { "auto"sv, "never"sv, "always"sv, "exceptZero"sv, "negative"sv }, "auto"sv));
|
||||
auto sign_display = TRY(get_option(vm, *options, vm.names.signDisplay, OptionType::String, { "auto"sv, "never"sv, "always"sv, "exceptZero"sv, "negative"sv }, u"auto"sv));
|
||||
|
||||
// 25. Set numberFormat.[[SignDisplay]] to signDisplay.
|
||||
number_format->set_sign_display(sign_display.as_string().utf16_string_view());
|
||||
|
|
@ -172,7 +172,7 @@ ThrowCompletionOr<GC::Ref<Object>> NumberFormatConstructor::construct(FunctionOb
|
|||
|
||||
// Non-standard, create an ICU number formatter for this Intl object.
|
||||
auto formatter = Unicode::NumberFormat::create(
|
||||
result.icu_locale,
|
||||
result.icu_locale.utf16_view().bytes(),
|
||||
number_format->display_options(),
|
||||
number_format->rounding_options());
|
||||
number_format->set_formatter(move(formatter));
|
||||
|
|
@ -212,14 +212,14 @@ ThrowCompletionOr<void> set_number_format_digit_options(VM& vm, NumberFormatBase
|
|||
return vm.throw_completion<RangeError>(ErrorType::IntlInvalidRoundingIncrement, *rounding_increment);
|
||||
|
||||
// 9. Let roundingMode be ? GetOption(options, "roundingMode", STRING, « "ceil", "floor", "expand", "trunc", "halfCeil", "halfFloor", "halfExpand", "halfTrunc", "halfEven" », "halfExpand").
|
||||
auto rounding_mode = TRY(get_option(vm, options, vm.names.roundingMode, OptionType::String, { "ceil"sv, "floor"sv, "expand"sv, "trunc"sv, "halfCeil"sv, "halfFloor"sv, "halfExpand"sv, "halfTrunc"sv, "halfEven"sv }, "halfExpand"sv));
|
||||
auto rounding_mode = TRY(get_option(vm, options, vm.names.roundingMode, OptionType::String, { "ceil"sv, "floor"sv, "expand"sv, "trunc"sv, "halfCeil"sv, "halfFloor"sv, "halfExpand"sv, "halfTrunc"sv, "halfEven"sv }, u"halfExpand"sv));
|
||||
|
||||
// 10. Let roundingPriority be ? GetOption(options, "roundingPriority", STRING, « "auto", "morePrecision", "lessPrecision" », "auto").
|
||||
auto rounding_priority_option = TRY(get_option(vm, options, vm.names.roundingPriority, OptionType::String, { "auto"sv, "morePrecision"sv, "lessPrecision"sv }, "auto"sv));
|
||||
auto rounding_priority_option = TRY(get_option(vm, options, vm.names.roundingPriority, OptionType::String, { "auto"sv, "morePrecision"sv, "lessPrecision"sv }, u"auto"sv));
|
||||
auto rounding_priority = rounding_priority_option.as_string().utf16_string_view();
|
||||
|
||||
// 11. Let trailingZeroDisplay be ? GetOption(options, "trailingZeroDisplay", STRING, « "auto", "stripIfInteger" », "auto").
|
||||
auto trailing_zero_display = TRY(get_option(vm, options, vm.names.trailingZeroDisplay, OptionType::String, { "auto"sv, "stripIfInteger"sv }, "auto"sv));
|
||||
auto trailing_zero_display = TRY(get_option(vm, options, vm.names.trailingZeroDisplay, OptionType::String, { "auto"sv, "stripIfInteger"sv }, u"auto"sv));
|
||||
|
||||
// 12. NOTE: All fields required by SetNumberFormatDigitOptions have now been read from options. The remainder of this AO interprets the options and may throw exceptions.
|
||||
|
||||
|
|
@ -390,7 +390,7 @@ ThrowCompletionOr<void> set_number_format_digit_options(VM& vm, NumberFormatBase
|
|||
ThrowCompletionOr<void> set_number_format_unit_options(VM& vm, NumberFormat& intl_object, Object const& options)
|
||||
{
|
||||
// 1. Let style be ? GetOption(options, "style", STRING, « "decimal", "percent", "currency", "unit" », "decimal").
|
||||
auto style = TRY(get_option(vm, options, vm.names.style, OptionType::String, { "decimal"sv, "percent"sv, "currency"sv, "unit"sv }, "decimal"sv));
|
||||
auto style = TRY(get_option(vm, options, vm.names.style, OptionType::String, { "decimal"sv, "percent"sv, "currency"sv, "unit"sv }, u"decimal"sv));
|
||||
|
||||
// 2. Set intlObj.[[Style]] to style.
|
||||
intl_object.set_style(style.as_string().utf16_string_view());
|
||||
|
|
@ -411,10 +411,10 @@ ThrowCompletionOr<void> set_number_format_unit_options(VM& vm, NumberFormat& int
|
|||
}
|
||||
|
||||
// 6. Let currencyDisplay be ? GetOption(options, "currencyDisplay", STRING, « "code", "symbol", "narrowSymbol", "name" », "symbol").
|
||||
auto currency_display = TRY(get_option(vm, options, vm.names.currencyDisplay, OptionType::String, { "code"sv, "symbol"sv, "narrowSymbol"sv, "name"sv }, "symbol"sv));
|
||||
auto currency_display = TRY(get_option(vm, options, vm.names.currencyDisplay, OptionType::String, { "code"sv, "symbol"sv, "narrowSymbol"sv, "name"sv }, u"symbol"sv));
|
||||
|
||||
// 7. Let currencySign be ? GetOption(options, "currencySign", STRING, « "standard", "accounting" », "standard").
|
||||
auto currency_sign = TRY(get_option(vm, options, vm.names.currencySign, OptionType::String, { "standard"sv, "accounting"sv }, "standard"sv));
|
||||
auto currency_sign = TRY(get_option(vm, options, vm.names.currencySign, OptionType::String, { "standard"sv, "accounting"sv }, u"standard"sv));
|
||||
|
||||
// 8. Let unit be ? GetOption(options, "unit", STRING, EMPTY, undefined).
|
||||
auto unit = TRY(get_option(vm, options, vm.names.unit, OptionType::String, {}, Empty {}));
|
||||
|
|
@ -432,7 +432,7 @@ ThrowCompletionOr<void> set_number_format_unit_options(VM& vm, NumberFormat& int
|
|||
}
|
||||
|
||||
// 11. Let unitDisplay be ? GetOption(options, "unitDisplay", STRING, « "short", "narrow", "long" », "short").
|
||||
auto unit_display = TRY(get_option(vm, options, vm.names.unitDisplay, OptionType::String, { "short"sv, "narrow"sv, "long"sv }, "short"sv));
|
||||
auto unit_display = TRY(get_option(vm, options, vm.names.unitDisplay, OptionType::String, { "short"sv, "narrow"sv, "long"sv }, u"short"sv));
|
||||
|
||||
// 12. If style is "currency", then
|
||||
if (intl_object.style() == Unicode::NumberFormatStyle::Currency) {
|
||||
|
|
@ -449,7 +449,7 @@ ThrowCompletionOr<void> set_number_format_unit_options(VM& vm, NumberFormat& int
|
|||
// 13. If style is "unit", then
|
||||
if (intl_object.style() == Unicode::NumberFormatStyle::Unit) {
|
||||
// a. Set intlObj.[[Unit]] to unit.
|
||||
intl_object.set_unit(MUST(unit.as_string().utf16_string_view().to_utf8()));
|
||||
intl_object.set_unit(unit.as_string().utf16_string());
|
||||
|
||||
// b. Set intlObj.[[UnitDisplay]] to unitDisplay.
|
||||
intl_object.set_unit_display(unit_display.as_string().utf16_string_view());
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ void NumberFormatFunction::initialize(Realm& realm)
|
|||
|
||||
Base::initialize(realm);
|
||||
define_direct_property(vm.names.length, Value(1), Attribute::Configurable);
|
||||
define_direct_property(vm.names.name, PrimitiveString::create(vm, String {}), Attribute::Configurable);
|
||||
define_direct_property(vm.names.name, PrimitiveString::create(vm, Utf16String {}), Attribute::Configurable);
|
||||
}
|
||||
|
||||
ThrowCompletionOr<Value> NumberFormatFunction::call()
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ void NumberFormatPrototype::initialize(Realm& realm)
|
|||
auto& vm = this->vm();
|
||||
|
||||
// 16.3.7 Intl.NumberFormat.prototype [ %Symbol.toStringTag% ], https://tc39.es/ecma402/#sec-intl.numberformat.prototype-%symbol.tostringtag%
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Intl.NumberFormat"_string), Attribute::Configurable);
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Intl.NumberFormat"_utf16_fly_string), Attribute::Configurable);
|
||||
|
||||
define_native_accessor(realm, vm.names.format, format, nullptr, Attribute::Configurable);
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ PluralRules::PluralRules(Object& prototype)
|
|||
}
|
||||
|
||||
// 17.2.3 Internal slots, https://tc39.es/ecma402/#sec-intl.pluralrules-internal-slots
|
||||
ReadonlySpan<StringView> PluralRules::relevant_extension_keys() const
|
||||
ReadonlySpan<Utf16View> PluralRules::relevant_extension_keys() const
|
||||
{
|
||||
// The value of the [[RelevantExtensionKeys]] internal slot is « ».
|
||||
return {};
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/StringView.h>
|
||||
#include <AK/Utf16String.h>
|
||||
#include <AK/Utf16View.h>
|
||||
#include <LibJS/Runtime/Completion.h>
|
||||
#include <LibJS/Runtime/Intl/NumberFormat.h>
|
||||
|
|
@ -22,12 +23,11 @@ class PluralRules final : public NumberFormatBase {
|
|||
public:
|
||||
virtual ~PluralRules() override = default;
|
||||
|
||||
virtual ReadonlySpan<StringView> relevant_extension_keys() const override;
|
||||
virtual ReadonlySpan<Utf16View> relevant_extension_keys() const override;
|
||||
virtual ReadonlySpan<ResolutionOptionDescriptor> resolution_option_descriptors(VM&) const override;
|
||||
|
||||
Unicode::PluralForm type() const { return m_type; }
|
||||
StringView type_string() const { return Unicode::plural_form_to_string(m_type); }
|
||||
void set_type(StringView type) { m_type = Unicode::plural_form_from_string(type); }
|
||||
Utf16String type_string() const { return Unicode::plural_form_to_string(m_type); }
|
||||
void set_type(Utf16View type) { m_type = Unicode::plural_form_from_string(type); }
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -64,19 +64,19 @@ ThrowCompletionOr<GC::Ref<Object>> PluralRulesConstructor::construct(FunctionObj
|
|||
plural_rules->set_locale(move(result.locale));
|
||||
|
||||
// 7. Let t be ? GetOption(options, "type", string, « "cardinal", "ordinal" », "cardinal").
|
||||
auto type = TRY(get_option(vm, *options, vm.names.type, OptionType::String, AK::Array { "cardinal"sv, "ordinal"sv }, "cardinal"sv));
|
||||
auto type = TRY(get_option(vm, *options, vm.names.type, OptionType::String, AK::Array { "cardinal"sv, "ordinal"sv }, u"cardinal"sv));
|
||||
|
||||
// 8. Set pluralRules.[[Type]] to t.
|
||||
plural_rules->set_type(type.as_string().utf16_string_view());
|
||||
|
||||
// 9. Let notation be ? GetOption(options, "notation", string, « "standard", "scientific", "engineering", "compact" », "standard").
|
||||
auto notation = TRY(get_option(vm, *options, vm.names.notation, OptionType::String, { "standard"sv, "scientific"sv, "engineering"sv, "compact"sv }, "standard"sv));
|
||||
auto notation = TRY(get_option(vm, *options, vm.names.notation, OptionType::String, { "standard"sv, "scientific"sv, "engineering"sv, "compact"sv }, u"standard"sv));
|
||||
|
||||
// 10. Set pluralRules.[[Notation]] to notation.
|
||||
plural_rules->set_notation(notation.as_string().utf16_string_view());
|
||||
|
||||
// 11. Let compactDisplay be ? GetOption(options, "compactDisplay", string, « "short", "long" », "short").
|
||||
auto compact_display = TRY(get_option(vm, *options, vm.names.compactDisplay, OptionType::String, { "short"sv, "long"sv }, "short"sv));
|
||||
auto compact_display = TRY(get_option(vm, *options, vm.names.compactDisplay, OptionType::String, { "short"sv, "long"sv }, u"short"sv));
|
||||
|
||||
// 12. If notation is "compact", then
|
||||
if (plural_rules->notation() == Unicode::Notation::Compact) {
|
||||
|
|
@ -89,7 +89,7 @@ ThrowCompletionOr<GC::Ref<Object>> PluralRulesConstructor::construct(FunctionObj
|
|||
|
||||
// Non-standard, create an ICU number formatter for this Intl object.
|
||||
auto formatter = Unicode::NumberFormat::create(
|
||||
result.icu_locale,
|
||||
result.icu_locale.utf16_view().bytes(),
|
||||
plural_rules->display_options(),
|
||||
plural_rules->rounding_options());
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ void PluralRulesPrototype::initialize(Realm& realm)
|
|||
auto& vm = this->vm();
|
||||
|
||||
// 17.3.5 Intl.PluralRules.prototype [ %Symbol.toStringTag% ], https://tc39.es/ecma402/#sec-intl.pluralrules.prototype-%symbol.tostringtag%
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Intl.PluralRules"_string), Attribute::Configurable);
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Intl.PluralRules"_utf16_fly_string), Attribute::Configurable);
|
||||
|
||||
u8 attr = Attribute::Writable | Attribute::Configurable;
|
||||
define_native_function(realm, vm.names.resolvedOptions, resolved_options, 0, attr);
|
||||
|
|
|
|||
|
|
@ -21,10 +21,10 @@ RelativeTimeFormat::RelativeTimeFormat(Object& prototype)
|
|||
}
|
||||
|
||||
// 18.2.3 Internal slots, https://tc39.es/ecma402/#sec-Intl.RelativeTimeFormat-internal-slots
|
||||
ReadonlySpan<StringView> RelativeTimeFormat::relevant_extension_keys() const
|
||||
ReadonlySpan<Utf16View> RelativeTimeFormat::relevant_extension_keys() const
|
||||
{
|
||||
// The value of the [[RelevantExtensionKeys]] internal slot is « "nu" ».
|
||||
static constexpr AK::Array keys { "nu"sv };
|
||||
static constexpr AK::Array<Utf16View, 1> keys { "nu"sv };
|
||||
return keys;
|
||||
}
|
||||
|
||||
|
|
@ -131,7 +131,7 @@ ThrowCompletionOr<GC::Ref<Array>> format_relative_time_to_parts(VM& vm, Relative
|
|||
auto object = Object::create(realm, realm.intrinsics().object_prototype());
|
||||
|
||||
// b. Perform ! CreateDataPropertyOrThrow(O, "type", part.[[Type]]).
|
||||
MUST(object->create_data_property_or_throw(vm.names.type, PrimitiveString::create(vm, part.type)));
|
||||
MUST(object->create_data_property_or_throw(vm.names.type, PrimitiveString::create(vm, move(part.type))));
|
||||
|
||||
// c. Perform ! CreateDataPropertyOrThrow(O, "value", part.[[Value]]).
|
||||
MUST(object->create_data_property_or_throw(vm.names.value, PrimitiveString::create(vm, move(part.value))));
|
||||
|
|
@ -139,7 +139,7 @@ ThrowCompletionOr<GC::Ref<Array>> format_relative_time_to_parts(VM& vm, Relative
|
|||
// d. If part.[[Unit]] is not empty, then
|
||||
if (!part.unit.is_empty()) {
|
||||
// i. Perform ! CreateDataPropertyOrThrow(O, "unit", part.[[Unit]]).
|
||||
MUST(object->create_data_property_or_throw(vm.names.unit, PrimitiveString::create(vm, part.unit)));
|
||||
MUST(object->create_data_property_or_throw(vm.names.unit, PrimitiveString::create(vm, move(part.unit))));
|
||||
}
|
||||
|
||||
// e. Perform ! CreateDataPropertyOrThrow(result, ! ToString(n), O).
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/String.h>
|
||||
#include <AK/StringView.h>
|
||||
#include <AK/Utf16String.h>
|
||||
#include <AK/Utf16View.h>
|
||||
#include <LibJS/Runtime/Completion.h>
|
||||
#include <LibJS/Runtime/Intl/IntlObject.h>
|
||||
|
|
@ -23,24 +23,22 @@ class RelativeTimeFormat final : public IntlObject {
|
|||
public:
|
||||
virtual ~RelativeTimeFormat() override = default;
|
||||
|
||||
virtual ReadonlySpan<StringView> relevant_extension_keys() const override;
|
||||
virtual ReadonlySpan<Utf16View> relevant_extension_keys() const override;
|
||||
virtual ReadonlySpan<ResolutionOptionDescriptor> resolution_option_descriptors(VM&) const override;
|
||||
|
||||
String const& locale() const { return m_locale; }
|
||||
void set_locale(String locale) { m_locale = move(locale); }
|
||||
Utf16String const& locale() const { return m_locale; }
|
||||
void set_locale(Utf16String locale) { m_locale = move(locale); }
|
||||
|
||||
String const& numbering_system() const { return m_numbering_system; }
|
||||
void set_numbering_system(String numbering_system) { m_numbering_system = move(numbering_system); }
|
||||
Utf16String const& numbering_system() const { return m_numbering_system; }
|
||||
void set_numbering_system(Utf16String numbering_system) { m_numbering_system = move(numbering_system); }
|
||||
|
||||
Unicode::Style style() const { return m_style; }
|
||||
void set_style(StringView style) { m_style = Unicode::style_from_string(style); }
|
||||
void set_style(Utf16View style) { m_style = Unicode::style_from_string(style); }
|
||||
StringView style_string() const { return Unicode::style_to_string(m_style); }
|
||||
Utf16String style_string() const { return Unicode::style_to_string(m_style); }
|
||||
|
||||
Unicode::NumericDisplay numeric() const { return m_numeric; }
|
||||
void set_numeric(StringView numeric) { m_numeric = Unicode::numeric_display_from_string(numeric); }
|
||||
void set_numeric(Utf16View numeric) { m_numeric = Unicode::numeric_display_from_string(numeric); }
|
||||
StringView numeric_string() const { return Unicode::numeric_display_to_string(m_numeric); }
|
||||
Utf16String numeric_string() const { return Unicode::numeric_display_to_string(m_numeric); }
|
||||
|
||||
Unicode::RelativeTimeFormat const& formatter() const { return *m_formatter; }
|
||||
void set_formatter(NonnullOwnPtr<Unicode::RelativeTimeFormat> formatter) { m_formatter = move(formatter); }
|
||||
|
|
@ -48,8 +46,8 @@ public:
|
|||
private:
|
||||
explicit RelativeTimeFormat(Object& prototype);
|
||||
|
||||
String m_locale; // [[Locale]]
|
||||
String m_numbering_system; // [[NumberingSystem]]
|
||||
Utf16String m_locale; // [[Locale]]
|
||||
Utf16String m_numbering_system; // [[NumberingSystem]]
|
||||
Unicode::Style m_style { Unicode::Style::Long }; // [[Style]]
|
||||
Unicode::NumericDisplay m_numeric { Unicode::NumericDisplay::Always }; // [[Numeric]]
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ ThrowCompletionOr<GC::Ref<Object>> RelativeTimeFormatConstructor::construct(Func
|
|||
auto [options, result, _] = TRY(resolve_options(vm, relative_time_format, locales_value, options_value, SpecialBehaviors::CoerceOptions));
|
||||
|
||||
// 6. Let locale be r.[[Locale]].
|
||||
auto locale = move(result.locale);
|
||||
auto locale = result.locale;
|
||||
|
||||
// 7. Set relativeTimeFormat.[[Locale]] to locale.
|
||||
relative_time_format->set_locale(locale);
|
||||
|
|
@ -68,17 +68,17 @@ ThrowCompletionOr<GC::Ref<Object>> RelativeTimeFormatConstructor::construct(Func
|
|||
// 8. Set relativeTimeFormat.[[LocaleData]] to r.[[LocaleData]].
|
||||
|
||||
// 9. Set relativeTimeFormat.[[NumberingSystem]] to r.[[nu]].
|
||||
if (auto* resolved_numbering_system = result.nu.get_pointer<String>())
|
||||
if (auto* resolved_numbering_system = result.nu.get_pointer<Utf16String>())
|
||||
relative_time_format->set_numbering_system(move(*resolved_numbering_system));
|
||||
|
||||
// 10. Let style be ? GetOption(options, "style", STRING, « "long", "short", "narrow" », "long").
|
||||
auto style = TRY(get_option(vm, *options, vm.names.style, OptionType::String, { "long"sv, "short"sv, "narrow"sv }, "long"sv));
|
||||
auto style = TRY(get_option(vm, *options, vm.names.style, OptionType::String, { "long"sv, "short"sv, "narrow"sv }, u"long"sv));
|
||||
|
||||
// 11. Set relativeTimeFormat.[[Style]] to style.
|
||||
relative_time_format->set_style(style.as_string().utf16_string_view());
|
||||
|
||||
// 12. Let numeric be ? GetOption(options, "numeric", STRING, « "always", "auto" », "always").
|
||||
auto numeric = TRY(get_option(vm, *options, vm.names.numeric, OptionType::String, { "always"sv, "auto"sv }, "always"sv));
|
||||
auto numeric = TRY(get_option(vm, *options, vm.names.numeric, OptionType::String, { "always"sv, "auto"sv }, u"always"sv));
|
||||
|
||||
// 13. Set relativeTimeFormat.[[Numeric]] to numeric.
|
||||
relative_time_format->set_numeric(numeric.as_string().utf16_string_view());
|
||||
|
|
@ -88,7 +88,7 @@ ThrowCompletionOr<GC::Ref<Object>> RelativeTimeFormatConstructor::construct(Func
|
|||
// 16. Let relativeTimeFormat.[[NumberFormat]] be ! Construct(%Intl.NumberFormat%, « locale, nfOptions »).
|
||||
// 17. Let relativeTimeFormat.[[PluralRules]] be ! Construct(%Intl.PluralRules%, « locale »).
|
||||
auto formatter = Unicode::RelativeTimeFormat::create(
|
||||
result.icu_locale,
|
||||
result.icu_locale.utf16_view().bytes(),
|
||||
relative_time_format->style());
|
||||
relative_time_format->set_formatter(move(formatter));
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ void RelativeTimeFormatPrototype::initialize(Realm& realm)
|
|||
auto& vm = this->vm();
|
||||
|
||||
// 18.3.5 Intl.RelativeTimeFormat.prototype [ %Symbol.toStringTag% ], https://tc39.es/ecma402/#sec-Intl.RelativeTimeFormat.prototype-toStringTag
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Intl.RelativeTimeFormat"_string), Attribute::Configurable);
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Intl.RelativeTimeFormat"_utf16_fly_string), Attribute::Configurable);
|
||||
|
||||
u8 attr = Attribute::Writable | Attribute::Configurable;
|
||||
define_native_function(realm, vm.names.resolvedOptions, resolved_options, 0, attr);
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ void SegmentIteratorPrototype::initialize(Realm& realm)
|
|||
auto& vm = this->vm();
|
||||
|
||||
// 19.6.2.2 %IntlSegmentIteratorPrototype% [ %Symbol.toStringTag% ], https://tc39.es/ecma402/#sec-%intlsegmentiteratorprototype%.%symbol.tostringtag%
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Segmenter String Iterator"_string), Attribute::Configurable);
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Segmenter String Iterator"_utf16_fly_string), Attribute::Configurable);
|
||||
|
||||
u8 attr = Attribute::Writable | Attribute::Configurable;
|
||||
define_native_function(realm, vm.names.next, next, 0, attr);
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ Segmenter::Segmenter(Object& prototype)
|
|||
}
|
||||
|
||||
// 19.2.3 Internal slots, https://tc39.es/ecma402/#sec-intl.segmenter-internal-slots
|
||||
ReadonlySpan<StringView> Segmenter::relevant_extension_keys() const
|
||||
ReadonlySpan<Utf16View> Segmenter::relevant_extension_keys() const
|
||||
{
|
||||
// The value of the [[RelevantExtensionKeys]] internal slot is « ».
|
||||
return {};
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/String.h>
|
||||
#include <AK/Utf16String.h>
|
||||
#include <AK/Utf16View.h>
|
||||
#include <LibJS/Runtime/Intl/IntlObject.h>
|
||||
#include <LibUnicode/Segmenter.h>
|
||||
|
|
@ -21,16 +21,15 @@ class Segmenter final : public IntlObject {
|
|||
public:
|
||||
virtual ~Segmenter() override = default;
|
||||
|
||||
virtual ReadonlySpan<StringView> relevant_extension_keys() const override;
|
||||
virtual ReadonlySpan<Utf16View> relevant_extension_keys() const override;
|
||||
virtual ReadonlySpan<ResolutionOptionDescriptor> resolution_option_descriptors(VM&) const override;
|
||||
|
||||
String const& locale() const { return m_locale; }
|
||||
void set_locale(String locale) { m_locale = move(locale); }
|
||||
Utf16String const& locale() const { return m_locale; }
|
||||
void set_locale(Utf16String locale) { m_locale = move(locale); }
|
||||
|
||||
Unicode::SegmenterGranularity segmenter_granularity() const { return m_segmenter_granularity; }
|
||||
void set_segmenter_granularity(StringView segmenter_granularity) { m_segmenter_granularity = Unicode::segmenter_granularity_from_string(segmenter_granularity); }
|
||||
void set_segmenter_granularity(Utf16View segmenter_granularity) { m_segmenter_granularity = Unicode::segmenter_granularity_from_string(segmenter_granularity); }
|
||||
StringView segmenter_granularity_string() const { return Unicode::segmenter_granularity_to_string(m_segmenter_granularity); }
|
||||
Utf16String segmenter_granularity_string() const { return Unicode::segmenter_granularity_to_string(m_segmenter_granularity); }
|
||||
|
||||
Unicode::Segmenter const& segmenter() const { return *m_segmenter; }
|
||||
void set_segmenter(NonnullOwnPtr<Unicode::Segmenter> segmenter) { m_segmenter = move(segmenter); }
|
||||
|
|
@ -38,7 +37,7 @@ public:
|
|||
private:
|
||||
explicit Segmenter(Object& prototype);
|
||||
|
||||
String m_locale; // [[Locale]]
|
||||
Utf16String m_locale; // [[Locale]]
|
||||
Unicode::SegmenterGranularity m_segmenter_granularity { Unicode::SegmenterGranularity::Grapheme }; // [[SegmenterGranularity]]
|
||||
|
||||
// Non-standard. Stores the ICU segmenter for the Intl object's segmentation options.
|
||||
|
|
|
|||
|
|
@ -64,12 +64,12 @@ ThrowCompletionOr<GC::Ref<Object>> SegmenterConstructor::construct(FunctionObjec
|
|||
segmenter->set_locale(move(result.locale));
|
||||
|
||||
// 8. Let granularity be ? GetOption(options, "granularity", string, « "grapheme", "word", "sentence" », "grapheme").
|
||||
auto granularity = TRY(get_option(vm, *options, vm.names.granularity, OptionType::String, { "grapheme"sv, "word"sv, "sentence"sv }, "grapheme"sv));
|
||||
auto granularity = TRY(get_option(vm, *options, vm.names.granularity, OptionType::String, { "grapheme"sv, "word"sv, "sentence"sv }, u"grapheme"sv));
|
||||
|
||||
// 9. Set segmenter.[[SegmenterGranularity]] to granularity.
|
||||
segmenter->set_segmenter_granularity(granularity.as_string().utf16_string_view());
|
||||
|
||||
auto locale_segmenter = Unicode::Segmenter::create(segmenter->locale(), segmenter->segmenter_granularity());
|
||||
auto locale_segmenter = Unicode::Segmenter::create(result.icu_locale.utf16_view().bytes(), segmenter->segmenter_granularity());
|
||||
segmenter->set_segmenter(move(locale_segmenter));
|
||||
|
||||
// 10. Return segmenter.
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ void SegmenterPrototype::initialize(Realm& realm)
|
|||
auto& vm = this->vm();
|
||||
|
||||
// 19.3.4 Intl.Segmenter.prototype [ %Symbol.toStringTag% ], https://tc39.es/ecma402/#sec-intl.segmenter.prototype-%symbol.tostringtag%
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Intl.Segmenter"_string), Attribute::Configurable);
|
||||
define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Intl.Segmenter"_utf16_fly_string), Attribute::Configurable);
|
||||
|
||||
u8 attr = Attribute::Writable | Attribute::Configurable;
|
||||
define_native_function(realm, vm.names.resolvedOptions, resolved_options, 0, attr);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/Array.h>
|
||||
#include <AK/StringView.h>
|
||||
#include <AK/Utf16View.h>
|
||||
|
||||
namespace JS::Intl {
|
||||
|
||||
|
|
@ -15,51 +15,51 @@ namespace JS::Intl {
|
|||
constexpr auto sanctioned_single_unit_identifiers()
|
||||
{
|
||||
return AK::Array {
|
||||
"acre"sv,
|
||||
"bit"sv,
|
||||
"byte"sv,
|
||||
"celsius"sv,
|
||||
"centimeter"sv,
|
||||
"day"sv,
|
||||
"degree"sv,
|
||||
"fahrenheit"sv,
|
||||
"fluid-ounce"sv,
|
||||
"foot"sv,
|
||||
"gallon"sv,
|
||||
"gigabit"sv,
|
||||
"gigabyte"sv,
|
||||
"gram"sv,
|
||||
"hectare"sv,
|
||||
"hour"sv,
|
||||
"inch"sv,
|
||||
"kilobit"sv,
|
||||
"kilobyte"sv,
|
||||
"kilogram"sv,
|
||||
"kilometer"sv,
|
||||
"liter"sv,
|
||||
"megabit"sv,
|
||||
"megabyte"sv,
|
||||
"meter"sv,
|
||||
"microsecond"sv,
|
||||
"mile"sv,
|
||||
"mile-scandinavian"sv,
|
||||
"milliliter"sv,
|
||||
"millimeter"sv,
|
||||
"millisecond"sv,
|
||||
"minute"sv,
|
||||
"month"sv,
|
||||
"nanosecond"sv,
|
||||
"ounce"sv,
|
||||
"percent"sv,
|
||||
"petabyte"sv,
|
||||
"pound"sv,
|
||||
"second"sv,
|
||||
"stone"sv,
|
||||
"terabit"sv,
|
||||
"terabyte"sv,
|
||||
"week"sv,
|
||||
"yard"sv,
|
||||
"year"sv,
|
||||
u"acre"sv,
|
||||
u"bit"sv,
|
||||
u"byte"sv,
|
||||
u"celsius"sv,
|
||||
u"centimeter"sv,
|
||||
u"day"sv,
|
||||
u"degree"sv,
|
||||
u"fahrenheit"sv,
|
||||
u"fluid-ounce"sv,
|
||||
u"foot"sv,
|
||||
u"gallon"sv,
|
||||
u"gigabit"sv,
|
||||
u"gigabyte"sv,
|
||||
u"gram"sv,
|
||||
u"hectare"sv,
|
||||
u"hour"sv,
|
||||
u"inch"sv,
|
||||
u"kilobit"sv,
|
||||
u"kilobyte"sv,
|
||||
u"kilogram"sv,
|
||||
u"kilometer"sv,
|
||||
u"liter"sv,
|
||||
u"megabit"sv,
|
||||
u"megabyte"sv,
|
||||
u"meter"sv,
|
||||
u"microsecond"sv,
|
||||
u"mile"sv,
|
||||
u"mile-scandinavian"sv,
|
||||
u"milliliter"sv,
|
||||
u"millimeter"sv,
|
||||
u"millisecond"sv,
|
||||
u"minute"sv,
|
||||
u"month"sv,
|
||||
u"nanosecond"sv,
|
||||
u"ounce"sv,
|
||||
u"percent"sv,
|
||||
u"petabyte"sv,
|
||||
u"pound"sv,
|
||||
u"second"sv,
|
||||
u"stone"sv,
|
||||
u"terabit"sv,
|
||||
u"terabyte"sv,
|
||||
u"week"sv,
|
||||
u"yard"sv,
|
||||
u"year"sv,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -323,7 +323,7 @@ void Intrinsics::initialize_intrinsics(Realm& realm)
|
|||
},
|
||||
0, Utf16FlyString {}, &realm);
|
||||
m_throw_type_error_function->define_direct_property(vm.names.length, Value(0), 0);
|
||||
m_throw_type_error_function->define_direct_property(vm.names.name, PrimitiveString::create(vm, String {}), 0);
|
||||
m_throw_type_error_function->define_direct_property(vm.names.name, PrimitiveString::create(vm, Utf16String {}), 0);
|
||||
MUST(m_throw_type_error_function->internal_prevent_extensions());
|
||||
|
||||
m_throw_type_error_accessor = Accessor::create(
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue