Commit 162c5b0f authored by Frank Tang's avatar Frank Tang Committed by Commit Bot

[Intl] Prototype Intl.DisplayNames

Design Doc https://shorturl.at/emEHW
I2I: http://shorturl.at/pKRUV

Bug: v8:8703
Change-Id: I9573b2ee6f1dce4dc594aa1df2753095f45af15e
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1848683Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Frank Tang <ftang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#65021}
parent a3b5229b
......@@ -2475,6 +2475,9 @@ v8_source_set("v8_base_without_compiler") {
"src/objects/js-date-time-format-inl.h",
"src/objects/js-date-time-format.cc",
"src/objects/js-date-time-format.h",
"src/objects/js-display-names-inl.h",
"src/objects/js-display-names.cc",
"src/objects/js-display-names.h",
"src/objects/js-generator-inl.h",
"src/objects/js-generator.h",
"src/objects/js-list-format-inl.h",
......@@ -3248,6 +3251,9 @@ v8_source_set("v8_base_without_compiler") {
"src/objects/js-date-time-format-inl.h",
"src/objects/js-date-time-format.cc",
"src/objects/js-date-time-format.h",
"src/objects/js-display-names-inl.h",
"src/objects/js-display-names.cc",
"src/objects/js-display-names.h",
"src/objects/js-list-format-inl.h",
"src/objects/js-list-format.cc",
"src/objects/js-list-format.h",
......
......@@ -8256,6 +8256,7 @@ class V8_EXPORT Isolate {
kRegExpMatchAllWithNonGlobalRegExp = 78,
kRegExpExecCalledOnSlowRegExp = 79,
kRegExpReplaceCalledOnSlowRegExp = 80,
kDisplayNames = 81,
// If you add new values here, you'll also need to update Chromium's:
// web_feature.mojom, use_counter_callback.cc, and enums.xml. V8 changes to
......
......@@ -1081,6 +1081,14 @@ namespace internal {
CPP(DateTimeFormatPrototypeResolvedOptions) \
/* ecma402 #sec-intl.datetimeformat.supportedlocalesof */ \
CPP(DateTimeFormatSupportedLocalesOf) \
/* ecma402 #sec-Intl.DisplayNames */ \
CPP(DisplayNamesConstructor) \
/* ecma402 #sec-Intl.DisplayNames.prototype.of */ \
CPP(DisplayNamesPrototypeOf) \
/* ecma402 #sec-Intl.DisplayNames.prototype.resolvedOptions */ \
CPP(DisplayNamesPrototypeResolvedOptions) \
/* ecma402 #sec-Intl.DisplayNames.supportedLocalesOf */ \
CPP(DisplayNamesSupportedLocalesOf) \
/* ecma402 #sec-intl.getcanonicallocales */ \
CPP(IntlGetCanonicalLocales) \
/* ecma402 #sec-intl-listformat-constructor */ \
......
......@@ -20,6 +20,7 @@
#include "src/objects/js-break-iterator-inl.h"
#include "src/objects/js-collator-inl.h"
#include "src/objects/js-date-time-format-inl.h"
#include "src/objects/js-display-names-inl.h"
#include "src/objects/js-list-format-inl.h"
#include "src/objects/js-locale-inl.h"
#include "src/objects/js-number-format-inl.h"
......@@ -387,6 +388,45 @@ Object CallOrConstructConstructor(BuiltinArguments args, Isolate* isolate,
}
} // namespace
// Intl.DisplayNames
BUILTIN(DisplayNamesConstructor) {
HandleScope scope(isolate);
return DisallowCallConstructor<JSDisplayNames>(
args, isolate, v8::Isolate::UseCounterFeature::kDisplayNames,
"Intl.DisplayNames");
}
BUILTIN(DisplayNamesPrototypeResolvedOptions) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSDisplayNames, holder,
"Intl.DisplayNames.prototype.resolvedOptions");
return *JSDisplayNames::ResolvedOptions(isolate, holder);
}
BUILTIN(DisplayNamesSupportedLocalesOf) {
HandleScope scope(isolate);
Handle<Object> locales = args.atOrUndefined(isolate, 1);
Handle<Object> options = args.atOrUndefined(isolate, 2);
RETURN_RESULT_OR_FAILURE(
isolate, Intl::SupportedLocalesOf(
isolate, "Intl.DisplayNames.supportedLocalesOf",
JSDisplayNames::GetAvailableLocales(), locales, options));
}
BUILTIN(DisplayNamesPrototypeOf) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSDisplayNames, holder, "Intl.DisplayNames.prototype.of");
Handle<Object> code_obj = args.atOrUndefined(isolate, 1);
RETURN_RESULT_OR_FAILURE(isolate,
JSDisplayNames::Of(isolate, holder, code_obj));
}
// Intl.NumberFormat
BUILTIN(NumberFormatConstructor) {
HandleScope scope(isolate);
......
......@@ -51,6 +51,7 @@ class JSAsyncGeneratorObject;
class JSCollator;
class JSCollection;
class JSDateTimeFormat;
class JSDisplayNames;
class JSListFormat;
class JSLocale;
class JSNumberFormat;
......
......@@ -210,6 +210,7 @@ Type::bitset BitsetType::Lub(const MapRefLike& map) {
case JS_V8_BREAK_ITERATOR_TYPE:
case JS_COLLATOR_TYPE:
case JS_DATE_TIME_FORMAT_TYPE:
case JS_DISPLAY_NAMES_TYPE:
case JS_LIST_FORMAT_TYPE:
case JS_LOCALE_TYPE:
case JS_NUMBER_FORMAT_TYPE:
......
......@@ -39,6 +39,7 @@
#include "src/objects/js-collection-inl.h"
#ifdef V8_INTL_SUPPORT
#include "src/objects/js-date-time-format-inl.h"
#include "src/objects/js-display-names-inl.h"
#endif // V8_INTL_SUPPORT
#include "src/objects/js-generator-inl.h"
#ifdef V8_INTL_SUPPORT
......@@ -1548,6 +1549,8 @@ USE_TORQUE_VERIFIER(JSCollator)
USE_TORQUE_VERIFIER(JSDateTimeFormat)
USE_TORQUE_VERIFIER(JSDisplayNames)
USE_TORQUE_VERIFIER(JSListFormat)
USE_TORQUE_VERIFIER(JSLocale)
......
......@@ -35,6 +35,7 @@
#include "src/objects/js-collection-inl.h"
#ifdef V8_INTL_SUPPORT
#include "src/objects/js-date-time-format-inl.h"
#include "src/objects/js-display-names-inl.h"
#endif // V8_INTL_SUPPORT
#include "src/objects/js-generator-inl.h"
#ifdef V8_INTL_SUPPORT
......@@ -2023,6 +2024,14 @@ void JSDateTimeFormat::JSDateTimeFormatPrint(std::ostream& os) { // NOLINT
JSObjectPrintBody(os, *this);
}
void JSDisplayNames::JSDisplayNamesPrint(std::ostream& os) { // NOLINT
JSObjectPrintHeader(os, *this, "JSDisplayNames");
os << "\n - internal: " << Brief(internal());
os << "\n - style: " << StyleAsString();
os << "\n - fallback: " << FallbackAsString();
JSObjectPrintBody(os, *this);
}
void JSListFormat::JSListFormatPrint(std::ostream& os) { // NOLINT
JSObjectPrintHeader(os, *this, "JSListFormat");
os << "\n - locale: " << Brief(locale());
......
......@@ -211,7 +211,9 @@ DEFINE_IMPLICATION(harmony_import_meta, harmony_dynamic_import)
V(harmony_top_level_await, "harmony top level await")
#ifdef V8_INTL_SUPPORT
#define HARMONY_INPROGRESS(V) HARMONY_INPROGRESS_BASE(V)
#define HARMONY_INPROGRESS(V) \
HARMONY_INPROGRESS_BASE(V) \
V(harmony_intl_displaynames, "Intl.DisplayNames")
#else
#define HARMONY_INPROGRESS(V) HARMONY_INPROGRESS_BASE(V)
#endif
......
......@@ -35,6 +35,7 @@
#include "src/objects/js-break-iterator.h"
#include "src/objects/js-collator.h"
#include "src/objects/js-date-time-format.h"
#include "src/objects/js-display-names.h"
#include "src/objects/js-list-format.h"
#include "src/objects/js-locale.h"
#include "src/objects/js-number-format.h"
......@@ -4531,6 +4532,43 @@ void Genesis::InitializeGlobal_harmony_intl_segmenter() {
}
}
void Genesis::InitializeGlobal_harmony_intl_displaynames() {
if (!FLAG_harmony_intl_displaynames) return;
Handle<JSObject> intl = Handle<JSObject>::cast(
JSReceiver::GetProperty(
isolate(),
Handle<JSReceiver>(native_context()->global_object(), isolate()),
factory()->InternalizeUtf8String("Intl"))
.ToHandleChecked());
Handle<JSFunction> display_names_fun = InstallFunction(
isolate(), intl, "DisplayNames", JS_DISPLAY_NAMES_TYPE,
JSDisplayNames::kHeaderSize, 0, factory()->the_hole_value(),
Builtins::kDisplayNamesConstructor);
display_names_fun->shared().set_length(0);
display_names_fun->shared().DontAdaptArguments();
InstallWithIntrinsicDefaultProto(isolate_, display_names_fun,
Context::INTL_DISPLAY_NAMES_FUNCTION_INDEX);
SimpleInstallFunction(isolate(), display_names_fun, "supportedLocalesOf",
Builtins::kDisplayNamesSupportedLocalesOf, 1, false);
{
// Setup %DisplayNamesPrototype%.
Handle<JSObject> prototype(
JSObject::cast(display_names_fun->instance_prototype()), isolate());
InstallToStringTag(isolate(), prototype, "Intl.DisplayNames");
SimpleInstallFunction(isolate(), prototype, "resolvedOptions",
Builtins::kDisplayNamesPrototypeResolvedOptions, 0,
false);
SimpleInstallFunction(isolate(), prototype, "of",
Builtins::kDisplayNamesPrototypeOf, 1, false);
}
}
#endif // V8_INTL_SUPPORT
Handle<JSFunction> Genesis::CreateArrayBuffer(
......
......@@ -23,6 +23,7 @@
V(_, currencyDisplay_string, "currencyDisplay") \
V(_, currencySign_string, "currencySign") \
V(_, dateStyle_string, "dateStyle") \
V(_, dateTimeField_string, "dateTimeField") \
V(_, day_string, "day") \
V(_, dayPeriod_string, "dayPeriod") \
V(_, decimal_string, "decimal") \
......@@ -33,6 +34,7 @@
V(_, exponentInteger_string, "exponentInteger") \
V(_, exponentMinusSign_string, "exponentMinusSign") \
V(_, exponentSeparator_string, "exponentSeparator") \
V(_, fallback_string, "fallback") \
V(_, first_string, "first") \
V(_, format_string, "format") \
V(_, fraction_string, "fraction") \
......
......@@ -160,6 +160,8 @@ enum ContextLookupFlags {
V(INTL_COLLATOR_FUNCTION_INDEX, JSFunction, intl_collator_function) \
V(INTL_DATE_TIME_FORMAT_FUNCTION_INDEX, JSFunction, \
intl_date_time_format_function) \
V(INTL_DISPLAY_NAMES_FUNCTION_INDEX, JSFunction, \
intl_display_names_function) \
V(INTL_NUMBER_FORMAT_FUNCTION_INDEX, JSFunction, \
intl_number_format_function) \
V(INTL_LOCALE_FUNCTION_INDEX, JSFunction, intl_locale_function) \
......
......@@ -1587,6 +1587,11 @@ bool Intl::IsWellFormedCalendar(const std::string& value) {
return JSLocale::Is38AlphaNumList(value);
}
// ecma402/#sec-iswellformedcurrencycode
bool Intl::IsWellFormedCurrency(const std::string& currency) {
return JSLocale::Is3Alpha(currency);
}
bool Intl::IsValidCalendar(const icu::Locale& locale,
const std::string& value) {
return IsValidExtension<icu::Calendar>(locale, "calendar", value);
......
......@@ -277,6 +277,9 @@ class Intl {
// Check the calendar is well formed.
static bool IsWellFormedCalendar(const std::string& value);
// Check the currency is well formed.
static bool IsWellFormedCurrency(const std::string& value);
struct ResolvedLocale {
std::string locale;
icu::Locale icu_locale;
......
......@@ -4,13 +4,14 @@
#include 'src/objects/js-break-iterator.h'
#include 'src/objects/js-collator.h'
#include 'src/objects/js-date-time-format.h'
#include 'src/objects/js-display-names.h'
#include 'src/objects/js-list-format.h'
#include 'src/objects/js-locale.h'
#include 'src/objects/js-number-format.h'
#include 'src/objects/js-objects.h'
#include 'src/objects/js-plural-rules.h'
#include 'src/objects/js-relative-time-format.h'
#include 'src/objects/js-date-time-format.h'
#include 'src/objects/js-list-format.h'
#include 'src/objects/js-locale.h'
#include 'src/objects/js-segment-iterator.h'
#include 'src/objects/js-segmenter.h'
......@@ -23,6 +24,11 @@ extern class JSDateTimeFormat extends JSObject {
flags: Smi;
}
extern class JSDisplayNames extends JSObject {
internal: Foreign; // Managed<DisplayNamesInternal>
flags: Smi;
}
extern class JSListFormat extends JSObject {
locale: String;
icu_formatter: Foreign; // Managed<icu::ListFormatter>
......
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_INTL_SUPPORT
#error Internationalization is expected to be enabled.
#endif // V8_INTL_SUPPORT
#ifndef V8_OBJECTS_JS_DISPLAY_NAMES_INL_H_
#define V8_OBJECTS_JS_DISPLAY_NAMES_INL_H_
#include "src/objects/js-display-names.h"
#include "src/objects/objects-inl.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
namespace v8 {
namespace internal {
ACCESSORS(JSDisplayNames, internal, Managed<DisplayNamesInternal>,
kInternalOffset)
OBJECT_CONSTRUCTORS_IMPL(JSDisplayNames, JSObject)
// Base display names accessors.
SMI_ACCESSORS(JSDisplayNames, flags, kFlagsOffset)
CAST_ACCESSOR(JSDisplayNames)
inline void JSDisplayNames::set_style(Style style) {
DCHECK_GE(StyleBits::kMax, style);
set_flags(StyleBits::update(flags(), style));
}
inline JSDisplayNames::Style JSDisplayNames::style() const {
return StyleBits::decode(flags());
}
inline void JSDisplayNames::set_fallback(Fallback fallback) {
DCHECK_GE(FallbackBits::kMax, fallback);
int hints = flags();
hints = FallbackBits::update(hints, fallback);
set_flags(hints);
}
inline JSDisplayNames::Fallback JSDisplayNames::fallback() const {
return FallbackBits::decode(flags());
}
} // namespace internal
} // namespace v8
#include "src/objects/object-macros-undef.h"
#endif // V8_OBJECTS_JS_DISPLAY_NAMES_INL_H_
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_INTL_SUPPORT
#error Internationalization is expected to be enabled.
#endif // V8_INTL_SUPPORT
#include <memory>
#include <vector>
#include "src/objects/js-display-names-inl.h"
#include "src/objects/js-display-names.h"
#include "src/execution/isolate.h"
#include "src/heap/factory.h"
#include "src/objects/intl-objects.h"
#include "src/objects/managed.h"
#include "src/objects/objects-inl.h"
#include "unicode/dtfmtsym.h"
#include "unicode/dtptngen.h"
#include "unicode/localebuilder.h"
#include "unicode/locdspnm.h"
#include "unicode/timezone.h"
#include "unicode/tznames.h"
#include "unicode/uloc.h"
#include "unicode/unistr.h"
#include "unicode/uscript.h"
namespace v8 {
namespace internal {
// Type: identifying the types of the display names.
//
// ecma402/#sec-properties-of-intl-displaynames-instances
enum class Type {
kLanguage,
kRegion,
kScript,
kCurrency,
kWeekday,
kMonth,
kQuarter,
kDayPeriod,
kDateTimeField
};
bool IsUnicodeScriptSubtag(const std::string& value) {
UErrorCode status = U_ZERO_ERROR;
icu::LocaleBuilder builder;
builder.setScript(value).build(status);
return U_SUCCESS(status);
}
bool IsUnicodeRegionSubtag(const std::string& value) {
UErrorCode status = U_ZERO_ERROR;
icu::LocaleBuilder builder;
builder.setRegion(value).build(status);
return U_SUCCESS(status);
}
UDisplayContext ToUDisplayContext(JSDisplayNames::Style style) {
switch (style) {
case JSDisplayNames::Style::kLong:
return UDISPCTX_LENGTH_FULL;
case JSDisplayNames::Style::kShort:
case JSDisplayNames::Style::kNarrow:
return UDISPCTX_LENGTH_SHORT;
}
}
// Abstract class for all different types.
class DisplayNamesInternal {
public:
DisplayNamesInternal() {}
virtual ~DisplayNamesInternal() {}
virtual const char* type() const = 0;
virtual icu::Locale locale() const = 0;
virtual Maybe<icu::UnicodeString> of(Isolate* isolate,
const char* code) const = 0;
virtual const char* calendar() const { return nullptr; }
};
class LocaleDisplayNamesCommon : public DisplayNamesInternal {
public:
LocaleDisplayNamesCommon(const icu::Locale& locale,
JSDisplayNames::Style style, bool fallback)
: style_(style) {
UDisplayContext sub =
fallback ? UDISPCTX_SUBSTITUTE : UDISPCTX_NO_SUBSTITUTE;
UDisplayContext display_context[] = {ToUDisplayContext(style_),
UDISPCTX_DIALECT_NAMES,
UDISPCTX_CAPITALIZATION_NONE, sub};
ldn_.reset(
icu::LocaleDisplayNames::createInstance(locale, display_context, 4));
}
virtual ~LocaleDisplayNamesCommon() {}
icu::Locale locale() const override { return ldn_->getLocale(); }
protected:
icu::LocaleDisplayNames* locale_display_names() const { return ldn_.get(); }
private:
std::unique_ptr<icu::LocaleDisplayNames> ldn_;
JSDisplayNames::Style style_;
};
class LanguageNames : public LocaleDisplayNamesCommon {
public:
LanguageNames(const icu::Locale& locale, JSDisplayNames::Style style,
bool fallback)
: LocaleDisplayNamesCommon(locale, style, fallback) {}
virtual ~LanguageNames() {}
const char* type() const override { return "language"; }
Maybe<icu::UnicodeString> of(Isolate* isolate,
const char* code) const override {
UErrorCode status = U_ZERO_ERROR;
icu::Locale l =
icu::Locale(icu::Locale::forLanguageTag(code, status).getBaseName());
std::string checked = l.toLanguageTag<std::string>(status);
if (U_FAILURE(status)) {
THROW_NEW_ERROR_RETURN_VALUE(
isolate, NewRangeError(MessageTemplate::kInvalidArgument),
Nothing<icu::UnicodeString>());
}
icu::UnicodeString result;
locale_display_names()->localeDisplayName(checked.c_str(), result);
return Just(result);
}
};
class RegionNames : public LocaleDisplayNamesCommon {
public:
RegionNames(const icu::Locale& locale, JSDisplayNames::Style style,
bool fallback)
: LocaleDisplayNamesCommon(locale, style, fallback) {}
virtual ~RegionNames() {}
const char* type() const override { return "region"; }
Maybe<icu::UnicodeString> of(Isolate* isolate,
const char* code) const override {
std::string code_str(code);
if (!IsUnicodeRegionSubtag(code_str)) {
THROW_NEW_ERROR_RETURN_VALUE(
isolate, NewRangeError(MessageTemplate::kInvalidArgument),
Nothing<icu::UnicodeString>());
}
icu::UnicodeString result;
locale_display_names()->regionDisplayName(code_str.c_str(), result);
return Just(result);
}
};
class ScriptNames : public LocaleDisplayNamesCommon {
public:
ScriptNames(const icu::Locale& locale, JSDisplayNames::Style style,
bool fallback)
: LocaleDisplayNamesCommon(locale, style, fallback) {}
virtual ~ScriptNames() {}
const char* type() const override { return "script"; }
Maybe<icu::UnicodeString> of(Isolate* isolate,
const char* code) const override {
std::string code_str(code);
if (!IsUnicodeScriptSubtag(code_str)) {
THROW_NEW_ERROR_RETURN_VALUE(
isolate, NewRangeError(MessageTemplate::kInvalidArgument),
Nothing<icu::UnicodeString>());
}
icu::UnicodeString result;
locale_display_names()->scriptDisplayName(code_str.c_str(), result);
return Just(result);
}
};
class CurrencyNames : public LocaleDisplayNamesCommon {
public:
CurrencyNames(const icu::Locale& locale, JSDisplayNames::Style style,
bool fallback)
: LocaleDisplayNamesCommon(locale, style, fallback) {}
virtual ~CurrencyNames() {}
const char* type() const override { return "currency"; }
Maybe<icu::UnicodeString> of(Isolate* isolate,
const char* code) const override {
std::string code_str(code);
if (!Intl::IsWellFormedCurrency(code_str)) {
THROW_NEW_ERROR_RETURN_VALUE(
isolate, NewRangeError(MessageTemplate::kInvalidArgument),
Nothing<icu::UnicodeString>());
}
icu::UnicodeString result;
locale_display_names()->keyValueDisplayName("currency", code_str.c_str(),
result);
return Just(result);
}
};
UDateTimePGDisplayWidth StyleToUDateTimePGDisplayWidth(
JSDisplayNames::Style style) {
switch (style) {
case JSDisplayNames::Style::kLong:
return UDATPG_WIDE;
case JSDisplayNames::Style::kShort:
return UDATPG_ABBREVIATED;
case JSDisplayNames::Style::kNarrow:
return UDATPG_NARROW;
}
}
UDateTimePatternField StringToUDateTimePatternField(const char* code) {
switch (code[0]) {
case 'd':
if (strcmp(code, "day") == 0) return UDATPG_DAY_FIELD;
if (strcmp(code, "dayPeriod") == 0) return UDATPG_DAYPERIOD_FIELD;
break;
case 'e':
if (strcmp(code, "era") == 0) return UDATPG_ERA_FIELD;
break;
case 'h':
if (strcmp(code, "hour") == 0) return UDATPG_HOUR_FIELD;
break;
case 'm':
if (strcmp(code, "minute") == 0) return UDATPG_MINUTE_FIELD;
if (strcmp(code, "month") == 0) return UDATPG_MONTH_FIELD;
break;
case 'q':
if (strcmp(code, "quarter") == 0) return UDATPG_QUARTER_FIELD;
break;
case 's':
if (strcmp(code, "second") == 0) return UDATPG_SECOND_FIELD;
break;
case 't':
if (strcmp(code, "timeZoneName") == 0) return UDATPG_ZONE_FIELD;
break;
case 'w':
if (strcmp(code, "weekOfYear") == 0) return UDATPG_WEEK_OF_YEAR_FIELD;
if (strcmp(code, "weekday") == 0) return UDATPG_WEEKDAY_FIELD;
break;
case 'y':
if (strcmp(code, "year") == 0) return UDATPG_YEAR_FIELD;
break;
default:
break;
}
UNREACHABLE();
}
class DateTimeFieldNames : public DisplayNamesInternal {
public:
DateTimeFieldNames(const icu::Locale& locale, JSDisplayNames::Style style)
: locale_(locale), width_(StyleToUDateTimePGDisplayWidth(style)) {
UErrorCode status = U_ZERO_ERROR;
generator_.reset(
icu::DateTimePatternGenerator::createInstance(locale_, status));
CHECK(U_SUCCESS(status));
}
virtual ~DateTimeFieldNames() {}
const char* type() const override { return "dateTimeField"; }
icu::Locale locale() const override { return locale_; }
Maybe<icu::UnicodeString> of(Isolate* isolate,
const char* code) const override {
UDateTimePatternField field = StringToUDateTimePatternField(code);
if (field == UDATPG_FIELD_COUNT) {
THROW_NEW_ERROR_RETURN_VALUE(
isolate, NewRangeError(MessageTemplate::kInvalidArgument),
Nothing<icu::UnicodeString>());
}
return Just(generator_->getFieldDisplayName(field, width_));
}
private:
icu::Locale locale_;
UDateTimePGDisplayWidth width_;
std::unique_ptr<icu::DateTimePatternGenerator> generator_;
};
icu::DateFormatSymbols::DtWidthType StyleToDtWidthType(
JSDisplayNames::Style style, Type type) {
switch (style) {
case JSDisplayNames::Style::kLong:
return icu::DateFormatSymbols::WIDE;
case JSDisplayNames::Style::kShort:
return icu::DateFormatSymbols::SHORT;
case JSDisplayNames::Style::kNarrow:
if (type == Type::kQuarter) {
return icu::DateFormatSymbols::ABBREVIATED;
} else {
return icu::DateFormatSymbols::NARROW;
}
}
}
class DateFormatSymbolsNames : public DisplayNamesInternal {
public:
DateFormatSymbolsNames(const char* type, const icu::Locale& locale,
const icu::UnicodeString* array, int32_t length,
const char* calendar)
: type_(type),
locale_(locale),
array_(array),
length_(length),
calendar_(calendar) {}
virtual ~DateFormatSymbolsNames() {}
const char* type() const override { return type_; }
icu::Locale locale() const override { return locale_; }
const char* calendar() const override {
if (calendar_.empty()) {
return nullptr;
}
return calendar_.c_str();
}
virtual int32_t ComputeIndex(const char* code) const = 0;
Maybe<icu::UnicodeString> of(Isolate* isolate,
const char* code) const override {
int32_t index = ComputeIndex(code);
if (index < 0 || index >= length_) {
THROW_NEW_ERROR_RETURN_VALUE(
isolate, NewRangeError(MessageTemplate::kInvalidArgument),
Nothing<icu::UnicodeString>());
}
return Just(array_[index]);
}
private:
const char* type_;
icu::Locale locale_;
const icu::UnicodeString* array_;
int32_t length_;
std::string calendar_;
};
class WeekdayNames : public DateFormatSymbolsNames {
public:
WeekdayNames(const char* type, const icu::Locale& locale,
const icu::UnicodeString* array, int32_t length,
const char* calendar)
: DateFormatSymbolsNames(type, locale, array, length, calendar) {}
virtual ~WeekdayNames() {}
int32_t ComputeIndex(const char* code) const override {
int32_t i = atoi(code);
if (i == 7) return 1;
if (i > 0 && i < 7) return i + 1;
return -1;
}
};
class MonthNames : public DateFormatSymbolsNames {
public:
MonthNames(const char* type, const icu::Locale& locale,
const icu::UnicodeString* array, int32_t length,
const char* calendar)
: DateFormatSymbolsNames(type, locale, array, length, calendar) {}
virtual ~MonthNames() {}
int32_t ComputeIndex(const char* code) const override {
return atoi(code) - 1;
}
};
class QuarterNames : public DateFormatSymbolsNames {
public:
QuarterNames(const char* type, const icu::Locale& locale,
const icu::UnicodeString* array, int32_t length,
const char* calendar)
: DateFormatSymbolsNames(type, locale, array, length, calendar) {}
virtual ~QuarterNames() {}
int32_t ComputeIndex(const char* code) const override {
return atoi(code) - 1;
}
};
class DayPeriodNames : public DateFormatSymbolsNames {
public:
DayPeriodNames(const char* type, const icu::Locale& locale,
const icu::UnicodeString* array, int32_t length,
const char* calendar)
: DateFormatSymbolsNames(type, locale, array, length, calendar) {}
virtual ~DayPeriodNames() {}
int32_t ComputeIndex(const char* code) const override {
if (strcmp("am", code) == 0) {
return 0;
} else if (strcmp("pm", code) == 0) {
return 1;
} else {
return -1;
}
}
};
const char* gWeekday = "weekday";
const char* gMonth = "month";
const char* gQuarter = "quarter";
const char* gDayPeriod = "dayPeriod";
DateFormatSymbolsNames* CreateDateFormatSymbolsNames(
const icu::Locale& locale, JSDisplayNames::Style style, Type type) {
UErrorCode status = U_ZERO_ERROR;
std::unique_ptr<icu::DateFormatSymbols> symbols(
icu::DateFormatSymbols::createForLocale(locale, status));
if (U_FAILURE(status)) {
return nullptr;
}
icu::DateFormatSymbols::DtWidthType width_type =
StyleToDtWidthType(style, type);
int32_t count = 0;
std::string calendar =
locale.getUnicodeKeywordValue<std::string>("ca", status);
switch (type) {
case Type::kMonth:
return new MonthNames(
gMonth, locale,
symbols->getMonths(count, icu::DateFormatSymbols::STANDALONE,
width_type),
count, calendar.c_str());
case Type::kWeekday:
return new WeekdayNames(
gWeekday, locale,
symbols->getWeekdays(count, icu::DateFormatSymbols::STANDALONE,
width_type),
count, calendar.c_str());
case Type::kQuarter:
return new QuarterNames(
gQuarter, locale,
symbols->getQuarters(count, icu::DateFormatSymbols::STANDALONE,
width_type),
count, calendar.c_str());
case Type::kDayPeriod:
return new DayPeriodNames(gDayPeriod, locale,
symbols->getAmPmStrings(count), count,
calendar.c_str());
default:
UNREACHABLE();
}
}
DisplayNamesInternal* CreateInternal(const icu::Locale& locale,
JSDisplayNames::Style style, Type type,
bool fallback) {
switch (type) {
case Type::kLanguage:
return new LanguageNames(locale, style, fallback);
case Type::kRegion:
return new RegionNames(locale, style, fallback);
case Type::kScript:
return new ScriptNames(locale, style, fallback);
case Type::kCurrency:
return new CurrencyNames(locale, style, fallback);
case Type::kDateTimeField:
return new DateTimeFieldNames(locale, style);
case Type::kMonth:
case Type::kWeekday:
case Type::kQuarter:
case Type::kDayPeriod:
return CreateDateFormatSymbolsNames(locale, style, type);
default:
UNREACHABLE();
}
}
// ecma402 #sec-Intl.DisplayNames
MaybeHandle<JSDisplayNames> JSDisplayNames::New(Isolate* isolate,
Handle<Map> map,
Handle<Object> locales,
Handle<Object> input_options) {
const char* service = "Intl.DisplayNames";
Factory* factory = isolate->factory();
Handle<JSReceiver> options;
// 3. Let requestedLocales be ? CanonicalizeLocaleList(locales).
Maybe<std::vector<std::string>> maybe_requested_locales =
Intl::CanonicalizeLocaleList(isolate, locales);
MAYBE_RETURN(maybe_requested_locales, Handle<JSDisplayNames>());
std::vector<std::string> requested_locales =
maybe_requested_locales.FromJust();
// 4. If options is undefined, then
if (input_options->IsUndefined(isolate)) {
// 4. a. Let options be ObjectCreate(null).
options = factory->NewJSObjectWithNullProto();
// 5. Else
} else {
// 5. a. Let options be ? ToObject(options).
ASSIGN_RETURN_ON_EXCEPTION(isolate, options,
Object::ToObject(isolate, input_options),
JSDisplayNames);
}
// Note: No need to create a record. It's not observable.
// 6. Let opt be a new Record.
// 7. Let localeData be %DisplayNames%.[[LocaleData]].
// 8. Let matcher be ? GetOption(options, "localeMatcher", "string", «
// "lookup", "best fit" », "best fit").
Maybe<Intl::MatcherOption> maybe_locale_matcher =
Intl::GetLocaleMatcher(isolate, options, "Intl.DisplayNames");
MAYBE_RETURN(maybe_locale_matcher, MaybeHandle<JSDisplayNames>());
// 9. Set opt.[[localeMatcher]] to matcher.
Intl::MatcherOption matcher = maybe_locale_matcher.FromJust();
std::unique_ptr<char[]> calendar_str = nullptr;
const std::vector<const char*> empty_values = {};
// 10. Let calendar be ? GetOption(options, "calendar",
// "string", undefined, undefined).
Maybe<bool> maybe_calendar = Intl::GetStringOption(
isolate, options, "calendar", empty_values, service, &calendar_str);
MAYBE_RETURN(maybe_calendar, MaybeHandle<JSDisplayNames>());
// 11. If calendar is not undefined, then
if (maybe_calendar.FromJust() && calendar_str != nullptr) {
// a. If calendar does not match the (3*8alphanum) *("-" (3*8alphanum))
// sequence, throw a RangeError exception.
if (!Intl::IsWellFormedCalendar(calendar_str.get())) {
THROW_NEW_ERROR(
isolate,
NewRangeError(MessageTemplate::kInvalid, factory->calendar_string(),
factory->NewStringFromAsciiChecked(calendar_str.get())),
JSDisplayNames);
}
}
// 12. Set opt.[[ca]] to calendar.
// ecma402/#sec-Intl.DisplayNames-internal-slots
// The value of the [[RelevantExtensionKeys]] internal slot is
// « "ca" ».
std::set<std::string> relevant_extension_keys = {"ca"};
// 13. Let r be ResolveLocale(%DisplayNames%.[[AvailableLocales]],
// requestedLocales, opt, %DisplayNames%.[[RelevantExtensionKeys]]).
Intl::ResolvedLocale r =
Intl::ResolveLocale(isolate, JSDisplayNames::GetAvailableLocales(),
requested_locales, matcher, relevant_extension_keys);
icu::Locale icu_locale = r.icu_locale;
UErrorCode status = U_ZERO_ERROR;
if (calendar_str != nullptr &&
Intl::IsValidCalendar(icu_locale, calendar_str.get())) {
icu_locale.setUnicodeKeywordValue("ca", calendar_str.get(), status);
CHECK(U_SUCCESS(status));
}
// 14. Let s be ? GetOption(options, "style", "string",
// «"long", "short", "narrow"», "long").
Maybe<Style> maybe_style = Intl::GetStringOption<Style>(
isolate, options, "style", "Intl.DisplayNames",
{"long", "short", "narrow"},
{Style::kLong, Style::kShort, Style::kNarrow}, Style::kLong);
MAYBE_RETURN(maybe_style, MaybeHandle<JSDisplayNames>());
Style style_enum = maybe_style.FromJust();
// 15. Set displayNames.[[Style]] to style.
// 16. Let type be ? GetOption(options, "type", "string", « "language",
// "region", "script", "currency", "weekday", "month", "quarter",
// "dayPeriod", "dateTimeField" », "language").
Maybe<Type> maybe_type = Intl::GetStringOption<Type>(
isolate, options, "type", "Intl.DisplayNames",
{"language", "region", "script", "currency", "weekday", "month",
"quarter", "dayPeriod", "dateTimeField"},
{
Type::kLanguage,
Type::kRegion,
Type::kScript,
Type::kCurrency,
Type::kWeekday,
Type::kMonth,
Type::kQuarter,
Type::kDayPeriod,
Type::kDateTimeField,
},
Type::kLanguage);
MAYBE_RETURN(maybe_type, MaybeHandle<JSDisplayNames>());
Type type_enum = maybe_type.FromJust();
// 17. Set displayNames.[[Type]] to type.
// 18. Let fallback be ? GetOption(options, "fallback", "string",
// « "code", "none" », "code").
Maybe<Fallback> maybe_fallback = Intl::GetStringOption<Fallback>(
isolate, options, "fallback", "Intl.DisplayNames", {"code", "none"},
{Fallback::kCode, Fallback::kNone}, Fallback::kCode);
MAYBE_RETURN(maybe_fallback, MaybeHandle<JSDisplayNames>());
Fallback fallback_enum = maybe_fallback.FromJust();
// 19. Set displayNames.[[Fallback]] to fallback.
// 20. Set displayNames.[[Locale]] to the value of r.[[Locale]].
// Let calendar be r.[[ca]].
// Set displayNames.[[Calendar]] to calendar.
// Let dataLocale be r.[[dataLocale]].
// Let dataLocaleData be localeData.[[<dataLocale>]].
// Let types be dataLocaleData.[[types]].
// Assert: types is a Record (see 1.3.3).
// Let typeFields be types.[[<type>]].
// Assert: typeFields is a Record (see 1.3.3).
// Let styleFields be typeFields.[[<style>]].
// Assert: styleFields is a Record (see 1.3.3).
// Set displayNames.[[Fields]] to styleFields.
DisplayNamesInternal* internal = CreateInternal(
icu_locale, style_enum, type_enum, fallback_enum == Fallback::kCode);
if (internal == nullptr) {
THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIcuError),
JSDisplayNames);
}
Handle<Managed<DisplayNamesInternal>> managed_internal =
Managed<DisplayNamesInternal>::FromRawPtr(isolate, 0, internal);
Handle<JSDisplayNames> display_names =
Handle<JSDisplayNames>::cast(factory->NewFastOrSlowJSObjectFromMap(map));
display_names->set_flags(0);
display_names->set_style(style_enum);
display_names->set_fallback(fallback_enum);
DisallowHeapAllocation no_gc;
display_names->set_internal(*managed_internal);
// Return displayNames.
return display_names;
}
// ecma402 #sec-Intl.DisplayNames.prototype.resolvedOptions
Handle<JSObject> JSDisplayNames::ResolvedOptions(
Isolate* isolate, Handle<JSDisplayNames> display_names) {
Factory* factory = isolate->factory();
// 4. Let options be ! ObjectCreate(%ObjectPrototype%).
Handle<JSObject> options = factory->NewJSObject(isolate->object_function());
DisplayNamesInternal* internal = display_names->internal().raw();
Maybe<std::string> maybe_locale = Intl::ToLanguageTag(internal->locale());
CHECK(maybe_locale.IsJust());
Handle<String> locale = isolate->factory()->NewStringFromAsciiChecked(
maybe_locale.FromJust().c_str());
Handle<String> style = display_names->StyleAsString();
Handle<String> type = factory->NewStringFromAsciiChecked(internal->type());
Handle<String> fallback = display_names->FallbackAsString();
CHECK(JSReceiver::CreateDataProperty(isolate, options,
factory->locale_string(), locale,
Just(kDontThrow))
.FromJust());
if (internal->calendar() != nullptr) {
CHECK(JSReceiver::CreateDataProperty(
isolate, options, factory->calendar_string(),
factory->NewStringFromAsciiChecked(internal->calendar()),
Just(kDontThrow))
.FromJust());
}
CHECK(JSReceiver::CreateDataProperty(
isolate, options, factory->style_string(), style, Just(kDontThrow))
.FromJust());
CHECK(JSReceiver::CreateDataProperty(isolate, options, factory->type_string(),
type, Just(kDontThrow))
.FromJust());
CHECK(JSReceiver::CreateDataProperty(isolate, options,
factory->fallback_string(), fallback,
Just(kDontThrow))
.FromJust());
return options;
}
// ecma402 #sec-Intl.DisplayNames.prototype.of
MaybeHandle<Object> JSDisplayNames::Of(Isolate* isolate,
Handle<JSDisplayNames> display_names,
Handle<Object> code_obj) {
Handle<String> code;
ASSIGN_RETURN_ON_EXCEPTION(isolate, code, Object::ToString(isolate, code_obj),
Object);
DisplayNamesInternal* internal = display_names->internal().raw();
Maybe<icu::UnicodeString> maybe_result =
internal->of(isolate, code->ToCString().get());
MAYBE_RETURN(maybe_result, Handle<Object>());
icu::UnicodeString result = maybe_result.FromJust();
if (result.isBogus()) {
return isolate->factory()->undefined_value();
}
return Intl::ToString(isolate, result).ToHandleChecked();
}
namespace {
struct CheckCalendar {
static const char* key() { return "calendar"; }
static const char* path() { return nullptr; }
};
} // namespace
const std::set<std::string>& JSDisplayNames::GetAvailableLocales() {
static base::LazyInstance<
Intl::AvailableLocales<icu::Locale, CheckCalendar>>::type
available_locales = LAZY_INSTANCE_INITIALIZER;
return available_locales.Pointer()->Get();
}
Handle<String> JSDisplayNames::StyleAsString() const {
switch (style()) {
case Style::kLong:
return GetReadOnlyRoots().long_string_handle();
case Style::kShort:
return GetReadOnlyRoots().short_string_handle();
case Style::kNarrow:
return GetReadOnlyRoots().narrow_string_handle();
}
UNREACHABLE();
}
Handle<String> JSDisplayNames::FallbackAsString() const {
switch (fallback()) {
case Fallback::kCode:
return GetReadOnlyRoots().code_string_handle();
case Fallback::kNone:
return GetReadOnlyRoots().none_string_handle();
}
UNREACHABLE();
}
} // namespace internal
} // namespace v8
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_INTL_SUPPORT
#error Internationalization is expected to be enabled.
#endif // V8_INTL_SUPPORT
#ifndef V8_OBJECTS_JS_DISPLAY_NAMES_H_
#define V8_OBJECTS_JS_DISPLAY_NAMES_H_
#include <set>
#include <string>
#include "src/execution/isolate.h"
#include "src/heap/factory.h"
#include "src/objects/managed.h"
#include "src/objects/objects.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
namespace v8 {
namespace internal {
class DisplayNamesInternal;
class JSDisplayNames : public JSObject {
public:
// Creates display names object with properties derived from input
// locales and options.
static MaybeHandle<JSDisplayNames> New(Isolate* isolate, Handle<Map> map,
Handle<Object> locales,
Handle<Object> options);
static Handle<JSObject> ResolvedOptions(Isolate* isolate,
Handle<JSDisplayNames> format_holder);
static MaybeHandle<Object> Of(Isolate* isolate, Handle<JSDisplayNames> holder,
Handle<Object> code_obj);
V8_EXPORT_PRIVATE static const std::set<std::string>& GetAvailableLocales();
Handle<String> StyleAsString() const;
Handle<String> FallbackAsString() const;
// Style: identifying the display names style used.
//
// ecma402/#sec-properties-of-intl-displaynames-instances
enum class Style {
kLong, // Everything spelled out.
kShort, // Abbreviations used when possible.
kNarrow // Use the shortest possible form.
};
inline void set_style(Style style);
inline Style style() const;
// Type: identifying the fallback of the display names.
//
// ecma402/#sec-properties-of-intl-displaynames-instances
enum class Fallback {
kCode,
kNone,
};
inline void set_fallback(Fallback fallback);
inline Fallback fallback() const;
DECL_CAST(JSDisplayNames)
// Bit positions in |flags|.
#define FLAGS_BIT_FIELDS(V, _) \
V(StyleBits, Style, 2, _) \
V(FallbackBits, Fallback, 1, _)
DEFINE_BIT_FIELDS(FLAGS_BIT_FIELDS)
#undef FLAGS_BIT_FIELDS
STATIC_ASSERT(Style::kLong <= StyleBits::kMax);
STATIC_ASSERT(Style::kShort <= StyleBits::kMax);
STATIC_ASSERT(Style::kNarrow <= StyleBits::kMax);
STATIC_ASSERT(Fallback::kCode <= FallbackBits::kMax);
STATIC_ASSERT(Fallback::kNone <= FallbackBits::kMax);
// [flags] Bit field containing various flags about the function.
DECL_INT_ACCESSORS(flags)
DECL_ACCESSORS(internal, Managed<DisplayNamesInternal>)
DECL_PRINTER(JSDisplayNames)
DECL_VERIFIER(JSDisplayNames)
// Layout description.
DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize,
TORQUE_GENERATED_JS_DISPLAY_NAMES_FIELDS)
OBJECT_CONSTRUCTORS(JSDisplayNames, JSObject);
};
} // namespace internal
} // namespace v8
#include "src/objects/object-macros-undef.h"
#endif // V8_OBJECTS_JS_DISPLAY_NAMES_H_
......@@ -179,6 +179,10 @@ bool JSLocale::Is38AlphaNumList(const std::string& value) {
JSLocale::Is38AlphaNumList(value.substr(found + 1));
}
bool JSLocale::Is3Alpha(const std::string& value) {
return IsAlpha(value, 3, 3);
}
// TODO(ftang) Replace the following check w/ icu::LocaleBuilder
// once ICU64 land in March 2019.
bool JSLocale::StartsWithUnicodeLanguageId(const std::string& value) {
......
......@@ -56,6 +56,9 @@ class JSLocale : public JSObject {
// "(3*8alphanum) *("-" (3*8alphanum)) sequence" sequence
static bool Is38AlphaNumList(const std::string& value);
// Help function to check well-formed "3alpha"
static bool Is3Alpha(const std::string& value);
DECL_CAST(JSLocale)
DECL_ACCESSORS(icu_locale, Managed<icu::Locale>)
......
......@@ -37,6 +37,7 @@
#include "src/objects/js-collection.h"
#ifdef V8_INTL_SUPPORT
#include "src/objects/js-date-time-format.h"
#include "src/objects/js-display-names.h"
#endif // V8_INTL_SUPPORT
#include "src/objects/js-generator-inl.h"
#ifdef V8_INTL_SUPPORT
......@@ -2161,6 +2162,8 @@ int JSObject::GetHeaderSize(InstanceType type,
return JSCollator::kHeaderSize;
case JS_DATE_TIME_FORMAT_TYPE:
return JSDateTimeFormat::kHeaderSize;
case JS_DISPLAY_NAMES_TYPE:
return JSDisplayNames::kHeaderSize;
case JS_LIST_FORMAT_TYPE:
return JSListFormat::kHeaderSize;
case JS_LOCALE_TYPE:
......@@ -5213,6 +5216,7 @@ bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
#ifdef V8_INTL_SUPPORT
case JS_COLLATOR_TYPE:
case JS_DATE_TIME_FORMAT_TYPE:
case JS_DISPLAY_NAMES_TYPE:
case JS_LIST_FORMAT_TYPE:
case JS_LOCALE_TYPE:
case JS_NUMBER_FORMAT_TYPE:
......
......@@ -287,6 +287,7 @@ VisitorId Map::GetVisitorId(Map map) {
case JS_V8_BREAK_ITERATOR_TYPE:
case JS_COLLATOR_TYPE:
case JS_DATE_TIME_FORMAT_TYPE:
case JS_DISPLAY_NAMES_TYPE:
case JS_LIST_FORMAT_TYPE:
case JS_LOCALE_TYPE:
case JS_NUMBER_FORMAT_TYPE:
......
......@@ -249,6 +249,7 @@ class ZoneForwardList;
V(JSV8BreakIterator) \
V(JSCollator) \
V(JSDateTimeFormat) \
V(JSDisplayNames) \
V(JSListFormat) \
V(JSLocale) \
V(JSNumberFormat) \
......
......@@ -947,6 +947,7 @@ ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3, T4 p4) {
case JS_V8_BREAK_ITERATOR_TYPE:
case JS_COLLATOR_TYPE:
case JS_DATE_TIME_FORMAT_TYPE:
case JS_DISPLAY_NAMES_TYPE:
case JS_LIST_FORMAT_TYPE:
case JS_LOCALE_TYPE:
case JS_NUMBER_FORMAT_TYPE:
......
......@@ -70,6 +70,7 @@
// - JSWeakSet
// - JSCollator // If V8_INTL_SUPPORT enabled.
// - JSDateTimeFormat // If V8_INTL_SUPPORT enabled.
// - JSDisplayNames // If V8_INTL_SUPPORT enabled.
// - JSListFormat // If V8_INTL_SUPPORT enabled.
// - JSLocale // If V8_INTL_SUPPORT enabled.
// - JSNumberFormat // If V8_INTL_SUPPORT enabled.
......
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-intl-displaynames
// Throws only once during construction.
// Check for all getters to prevent regression.
// Preserve the order of getter initialization.
let getCount = 0;
new Intl.DisplayNames(['en-US'], {
get localeMatcher() {
assertEquals(0, getCount++);
},
get style() {
assertEquals(1, getCount++);
},
get type() {
assertEquals(2, getCount++);
},
get fallback() {
assertEquals(3, getCount++);
},
});
assertEquals(4, getCount);
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-intl-displaynames
// DisplayNames constructor can't be called as function.
assertThrows(() => Intl.DisplayNames('sr'), TypeError);
assertDoesNotThrow(() => new Intl.DisplayNames('sr', {}));
assertDoesNotThrow(() => new Intl.DisplayNames([], {}));
assertDoesNotThrow(() => new Intl.DisplayNames(['fr', 'ar'], {}));
assertDoesNotThrow(() => new Intl.DisplayNames({0: 'ja', 1:'fr'}, {}));
assertDoesNotThrow(() => new Intl.DisplayNames({1: 'ja', 2:'fr'}, {}));
assertDoesNotThrow(() => new Intl.DisplayNames('sr'));
assertDoesNotThrow(() => new Intl.DisplayNames());
assertDoesNotThrow(
() => new Intl.DisplayNames(
'sr', {
localeMatcher: 'lookup',
style: 'short',
type: 'language',
fallback: 'code',
}));
assertDoesNotThrow(
() => new Intl.DisplayNames('sr', {localeMatcher: 'lookup'}));
assertDoesNotThrow(
() => new Intl.DisplayNames('sr', {localeMatcher: 'best fit'}));
assertThrows(
() => new Intl.DisplayNames('sr', {localeMatcher: 'hello'}),
RangeError);
assertThrows(
() => new Intl.DisplayNames('sr', {localeMatcher: 'look up'}),
RangeError);
assertThrows(
() => new Intl.DisplayNames('sr', {localeMatcher: 'bestfit'}),
RangeError);
assertDoesNotThrow(
() => new Intl.DisplayNames('sr', {style: 'long'}));
assertDoesNotThrow(
() => new Intl.DisplayNames('sr', {style: 'short'}));
assertDoesNotThrow(
() => new Intl.DisplayNames('sr', {style: 'narrow'}));
assertThrows(
() => new Intl.DisplayNames('sr', {style: 'giant'}),
RangeError);
assertDoesNotThrow(
() => new Intl.DisplayNames('sr', {fallback: 'code'}));
assertDoesNotThrow(
() => new Intl.DisplayNames('sr', {fallback: 'none'}));
assertThrows(
() => new Intl.DisplayNames('sr', {fallback: 'never'}),
RangeError);
assertDoesNotThrow(
() => new Intl.DisplayNames('sr', {type: 'language'}));
assertDoesNotThrow(
() => new Intl.DisplayNames('sr', {type: 'region'}));
assertDoesNotThrow(
() => new Intl.DisplayNames('sr', {type: 'script'}));
assertDoesNotThrow(
() => new Intl.DisplayNames('sr', {type: 'currency'}));
assertDoesNotThrow(
() => new Intl.DisplayNames('sr', {type: 'month'}));
assertDoesNotThrow(
() => new Intl.DisplayNames('sr', {type: 'weekday'}));
assertDoesNotThrow(
() => new Intl.DisplayNames('sr', {type: 'quarter'}));
assertDoesNotThrow(
() => new Intl.DisplayNames('sr', {type: 'dayPeriod'}));
assertDoesNotThrow(
() => new Intl.DisplayNames('sr', {type: 'dateTimeField'}));
assertThrows(
() => new Intl.DisplayNames('sr', {type: ''}),
RangeError);
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-intl-displaynames
let displayNames = new Intl.DisplayNames();
// The default style is 'long'
assertEquals('long', displayNames.resolvedOptions().style);
// The default type is 'language'
assertEquals('language', displayNames.resolvedOptions().type);
// The default fallback is 'code'
assertEquals('code', displayNames.resolvedOptions().fallback);
const styles = ["long", "short", "narrow"];
const types = ["language", "region", "script", "currency", "weekday", "month",
"quarter", "dayPeriod", "dateTimeField"];
const fallbacks = ["code", "none"];
styles.forEach(function(style) {
assertEquals(style,
(new Intl.DisplayNames(['sr'], {style})).resolvedOptions().style);
assertEquals(types[0],
(new Intl.DisplayNames(['sr'], {style})).resolvedOptions().type);
assertEquals(fallbacks[0],
(new Intl.DisplayNames(['sr'], {style})).resolvedOptions().fallback);
types.forEach(function(type) {
assertEquals(style,
(new Intl.DisplayNames(['sr'], {style, type})).resolvedOptions().style);
assertEquals(type,
(new Intl.DisplayNames(['sr'], {style, type})).resolvedOptions().type);
assertEquals(fallbacks[0],
(new Intl.DisplayNames(
['sr'], {style, type})).resolvedOptions().fallback);
fallbacks.forEach(function(fallback) {
assertEquals(style,
(new Intl.DisplayNames(
['sr'], {style, type, fallback})).resolvedOptions().style);
assertEquals(type,
(new Intl.DisplayNames(
['sr'], {style, type, fallback})).resolvedOptions().type);
assertEquals(fallback,
(new Intl.DisplayNames(
['sr'], {style, type, fallback})).resolvedOptions().fallback);
});
});
});
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-intl-displaynames
assertEquals(typeof Intl.DisplayNames.supportedLocalesOf, "function",
"Intl.DisplayNames.supportedLocalesOf should be a function");
var undef = Intl.DisplayNames.supportedLocalesOf();
assertEquals([], undef);
var empty = Intl.DisplayNames.supportedLocalesOf([]);
assertEquals([], empty);
var strLocale = Intl.DisplayNames.supportedLocalesOf('sr');
assertEquals('sr', strLocale[0]);
var multiLocale = ['sr-Thai-RS', 'de', 'zh-CN'];
assertEquals(multiLocale, Intl.DisplayNames.supportedLocalesOf(multiLocale));
......@@ -457,39 +457,6 @@
# https://bugs.chromium.org/p/v8/issues/detail?id=7472
'intl402/NumberFormat/currency-digits': [FAIL],
# https://bugs.chromium.org/p/v8/issues/detail?id=8703
'intl402/DisplayNames/ctor-custom-get-prototype-poison-throws': [FAIL],
'intl402/DisplayNames/ctor-custom-prototype': [FAIL],
'intl402/DisplayNames/ctor-default-prototype': [FAIL],
'intl402/DisplayNames/instance-extensible': [FAIL],
'intl402/DisplayNames/length': [FAIL],
'intl402/DisplayNames/locales-length-poison-throws': [FAIL],
'intl402/DisplayNames/locales-length-tolength-throws': [FAIL],
'intl402/DisplayNames/locales-symbol-length': [FAIL],
'intl402/DisplayNames/name': [FAIL],
'intl402/DisplayNames/options-fallback-abrupt-throws': [FAIL],
'intl402/DisplayNames/options-fallback-invalid-throws': [FAIL],
'intl402/DisplayNames/options-fallback-toString-abrupt-throws': [FAIL],
'intl402/DisplayNames/options-fallback-valid': [FAIL],
'intl402/DisplayNames/options-localeMatcher-abrupt-throws': [FAIL],
'intl402/DisplayNames/options-localeMatcher-invalid-throws': [FAIL],
'intl402/DisplayNames/options-localeMatcher-toString-abrupt-throws': [FAIL],
'intl402/DisplayNames/options-localeMatcher-valid': [FAIL],
'intl402/DisplayNames/options-random-properties-unchecked': [FAIL],
'intl402/DisplayNames/options-style-abrupt-throws': [FAIL],
'intl402/DisplayNames/options-style-invalid-throws': [FAIL],
'intl402/DisplayNames/options-style-toString-abrupt-throws': [FAIL],
'intl402/DisplayNames/options-style-valid': [FAIL],
'intl402/DisplayNames/options-type-abrupt-throws': [FAIL],
'intl402/DisplayNames/options-type-invalid-throws': [FAIL],
'intl402/DisplayNames/options-type-toString-abrupt-throws': [FAIL],
'intl402/DisplayNames/options-type-valid': [FAIL],
'intl402/DisplayNames/prop-desc': [FAIL],
'intl402/DisplayNames/proto': [FAIL],
'intl402/DisplayNames/proto-from-ctor-realm': [FAIL],
'intl402/DisplayNames/prototype/prop-desc': [FAIL],
'intl402/DisplayNames/prototype/Symbol.toStringTag': [FAIL],
# https://bugs.chromium.org/p/v8/issues/detail?id=7831
'language/statements/generators/generator-created-after-decl-inst': [FAIL],
'language/expressions/generators/generator-created-after-decl-inst': [FAIL],
......
......@@ -48,6 +48,7 @@ FEATURE_FLAGS = {
'Intl.DateTimeFormat-dayPeriod': '--harmony-intl-dateformat-day-period',
'Intl.DateTimeFormat-quarter': '--harmony-intl-dateformat-quarter',
'Intl.DateTimeFormat-fractionalSecondDigits': '--harmony-intl-dateformat-fractional-second-digits',
'Intl.DisplayNames': '--harmony-intl-displaynames',
'Symbol.prototype.description': '--harmony-symbol-description',
'export-star-as-namespace-from-module': '--harmony-namespace-exports',
'Promise.allSettled': '--harmony-promise-all-settled',
......
......@@ -52,6 +52,7 @@ const CATEGORIES = new Map([
'JS_GLOBAL_PROXY_TYPE',
'JS_COLLATOR_TYPE',
'JS_DATE_TIME_FORMAT_TYPE',
'JS_DISPLAY_NAMES_TYPE',
'JS_LIST_FORMAT_TYPE',
'JS_LOCALE_TYPE',
'JS_NUMBER_FORMAT_TYPE',
......
......@@ -161,31 +161,32 @@ INSTANCE_TYPES = {
1064: "JS_CONTEXT_EXTENSION_OBJECT_TYPE",
1065: "JS_DATE_TYPE",
1066: "JS_DATE_TIME_FORMAT_TYPE",
1067: "JS_ERROR_TYPE",
1068: "JS_FINALIZATION_GROUP_TYPE",
1069: "JS_FINALIZATION_GROUP_CLEANUP_ITERATOR_TYPE",
1070: "JS_LIST_FORMAT_TYPE",
1071: "JS_LOCALE_TYPE",
1072: "JS_MESSAGE_OBJECT_TYPE",
1073: "JS_NUMBER_FORMAT_TYPE",
1074: "JS_PLURAL_RULES_TYPE",
1075: "JS_PROMISE_TYPE",
1076: "JS_REG_EXP_TYPE",
1077: "JS_REG_EXP_STRING_ITERATOR_TYPE",
1078: "JS_RELATIVE_TIME_FORMAT_TYPE",
1079: "JS_SEGMENT_ITERATOR_TYPE",
1080: "JS_SEGMENTER_TYPE",
1081: "JS_STRING_ITERATOR_TYPE",
1082: "JS_V8_BREAK_ITERATOR_TYPE",
1083: "JS_WEAK_REF_TYPE",
1084: "WASM_EXCEPTION_OBJECT_TYPE",
1085: "WASM_GLOBAL_OBJECT_TYPE",
1086: "WASM_INSTANCE_OBJECT_TYPE",
1087: "WASM_MEMORY_OBJECT_TYPE",
1088: "WASM_MODULE_OBJECT_TYPE",
1089: "WASM_TABLE_OBJECT_TYPE",
1090: "JS_BOUND_FUNCTION_TYPE",
1091: "JS_FUNCTION_TYPE",
1067: "JS_DISPLAY_NAMES_TYPE",
1068: "JS_ERROR_TYPE",
1069: "JS_FINALIZATION_GROUP_TYPE",
1070: "JS_FINALIZATION_GROUP_CLEANUP_ITERATOR_TYPE",
1071: "JS_LIST_FORMAT_TYPE",
1072: "JS_LOCALE_TYPE",
1073: "JS_MESSAGE_OBJECT_TYPE",
1074: "JS_NUMBER_FORMAT_TYPE",
1075: "JS_PLURAL_RULES_TYPE",
1076: "JS_PROMISE_TYPE",
1077: "JS_REG_EXP_TYPE",
1078: "JS_REG_EXP_STRING_ITERATOR_TYPE",
1079: "JS_RELATIVE_TIME_FORMAT_TYPE",
1080: "JS_SEGMENT_ITERATOR_TYPE",
1081: "JS_SEGMENTER_TYPE",
1082: "JS_STRING_ITERATOR_TYPE",
1083: "JS_V8_BREAK_ITERATOR_TYPE",
1084: "JS_WEAK_REF_TYPE",
1085: "WASM_EXCEPTION_OBJECT_TYPE",
1086: "WASM_GLOBAL_OBJECT_TYPE",
1087: "WASM_INSTANCE_OBJECT_TYPE",
1088: "WASM_MEMORY_OBJECT_TYPE",
1089: "WASM_MODULE_OBJECT_TYPE",
1090: "WASM_TABLE_OBJECT_TYPE",
1091: "JS_BOUND_FUNCTION_TYPE",
1092: "JS_FUNCTION_TYPE",
}
# List of known V8 maps.
......@@ -280,56 +281,56 @@ KNOWN_MAPS = {
("read_only_space", 0x01d79): (92, "EnumCacheMap"),
("read_only_space", 0x01e11): (86, "ArrayBoilerplateDescriptionMap"),
("read_only_space", 0x01ff9): (95, "InterceptorInfoMap"),
("read_only_space", 0x04969): (71, "PromiseFulfillReactionJobTaskMap"),
("read_only_space", 0x049b1): (72, "PromiseRejectReactionJobTaskMap"),
("read_only_space", 0x049f9): (73, "CallableTaskMap"),
("read_only_space", 0x04a41): (74, "CallbackTaskMap"),
("read_only_space", 0x04a89): (75, "PromiseResolveThenableJobTaskMap"),
("read_only_space", 0x04ad1): (78, "FunctionTemplateInfoMap"),
("read_only_space", 0x04b19): (79, "ObjectTemplateInfoMap"),
("read_only_space", 0x04b61): (80, "AccessCheckInfoMap"),
("read_only_space", 0x04ba9): (81, "AccessorInfoMap"),
("read_only_space", 0x04bf1): (82, "AccessorPairMap"),
("read_only_space", 0x04c39): (83, "AliasedArgumentsEntryMap"),
("read_only_space", 0x04c81): (84, "AllocationMementoMap"),
("read_only_space", 0x04cc9): (87, "AsmWasmDataMap"),
("read_only_space", 0x04d11): (88, "AsyncGeneratorRequestMap"),
("read_only_space", 0x04d59): (90, "ClassPositionsMap"),
("read_only_space", 0x04da1): (91, "DebugInfoMap"),
("read_only_space", 0x04de9): (94, "FunctionTemplateRareDataMap"),
("read_only_space", 0x04e31): (97, "InterpreterDataMap"),
("read_only_space", 0x04e79): (98, "PromiseCapabilityMap"),
("read_only_space", 0x04ec1): (99, "PromiseReactionMap"),
("read_only_space", 0x04f09): (100, "PrototypeInfoMap"),
("read_only_space", 0x04f51): (101, "ScriptMap"),
("read_only_space", 0x04f99): (105, "SourcePositionTableWithFrameCacheMap"),
("read_only_space", 0x04fe1): (106, "SourceTextModuleInfoEntryMap"),
("read_only_space", 0x05029): (107, "StackFrameInfoMap"),
("read_only_space", 0x05071): (108, "StackTraceFrameMap"),
("read_only_space", 0x050b9): (109, "TemplateObjectDescriptionMap"),
("read_only_space", 0x05101): (110, "Tuple2Map"),
("read_only_space", 0x05149): (111, "Tuple3Map"),
("read_only_space", 0x05191): (112, "WasmCapiFunctionDataMap"),
("read_only_space", 0x051d9): (113, "WasmDebugInfoMap"),
("read_only_space", 0x05221): (114, "WasmExceptionTagMap"),
("read_only_space", 0x05269): (115, "WasmExportedFunctionDataMap"),
("read_only_space", 0x052b1): (116, "WasmIndirectFunctionTableMap"),
("read_only_space", 0x052f9): (117, "WasmJSFunctionDataMap"),
("read_only_space", 0x05341): (96, "InternalClassMap"),
("read_only_space", 0x05389): (103, "SmiPairMap"),
("read_only_space", 0x053d1): (102, "SmiBoxMap"),
("read_only_space", 0x05419): (104, "SortStateMap"),
("read_only_space", 0x05461): (85, "AllocationSiteWithWeakNextMap"),
("read_only_space", 0x054a9): (85, "AllocationSiteWithoutWeakNextMap"),
("read_only_space", 0x054f1): (76, "LoadHandler1Map"),
("read_only_space", 0x05539): (76, "LoadHandler2Map"),
("read_only_space", 0x05581): (76, "LoadHandler3Map"),
("read_only_space", 0x055c9): (77, "StoreHandler0Map"),
("read_only_space", 0x05611): (77, "StoreHandler1Map"),
("read_only_space", 0x05659): (77, "StoreHandler2Map"),
("read_only_space", 0x056a1): (77, "StoreHandler3Map"),
("read_only_space", 0x049a1): (71, "PromiseFulfillReactionJobTaskMap"),
("read_only_space", 0x049e9): (72, "PromiseRejectReactionJobTaskMap"),
("read_only_space", 0x04a31): (73, "CallableTaskMap"),
("read_only_space", 0x04a79): (74, "CallbackTaskMap"),
("read_only_space", 0x04ac1): (75, "PromiseResolveThenableJobTaskMap"),
("read_only_space", 0x04b09): (78, "FunctionTemplateInfoMap"),
("read_only_space", 0x04b51): (79, "ObjectTemplateInfoMap"),
("read_only_space", 0x04b99): (80, "AccessCheckInfoMap"),
("read_only_space", 0x04be1): (81, "AccessorInfoMap"),
("read_only_space", 0x04c29): (82, "AccessorPairMap"),
("read_only_space", 0x04c71): (83, "AliasedArgumentsEntryMap"),
("read_only_space", 0x04cb9): (84, "AllocationMementoMap"),
("read_only_space", 0x04d01): (87, "AsmWasmDataMap"),
("read_only_space", 0x04d49): (88, "AsyncGeneratorRequestMap"),
("read_only_space", 0x04d91): (90, "ClassPositionsMap"),
("read_only_space", 0x04dd9): (91, "DebugInfoMap"),
("read_only_space", 0x04e21): (94, "FunctionTemplateRareDataMap"),
("read_only_space", 0x04e69): (97, "InterpreterDataMap"),
("read_only_space", 0x04eb1): (98, "PromiseCapabilityMap"),
("read_only_space", 0x04ef9): (99, "PromiseReactionMap"),
("read_only_space", 0x04f41): (100, "PrototypeInfoMap"),
("read_only_space", 0x04f89): (101, "ScriptMap"),
("read_only_space", 0x04fd1): (105, "SourcePositionTableWithFrameCacheMap"),
("read_only_space", 0x05019): (106, "SourceTextModuleInfoEntryMap"),
("read_only_space", 0x05061): (107, "StackFrameInfoMap"),
("read_only_space", 0x050a9): (108, "StackTraceFrameMap"),
("read_only_space", 0x050f1): (109, "TemplateObjectDescriptionMap"),
("read_only_space", 0x05139): (110, "Tuple2Map"),
("read_only_space", 0x05181): (111, "Tuple3Map"),
("read_only_space", 0x051c9): (112, "WasmCapiFunctionDataMap"),
("read_only_space", 0x05211): (113, "WasmDebugInfoMap"),
("read_only_space", 0x05259): (114, "WasmExceptionTagMap"),
("read_only_space", 0x052a1): (115, "WasmExportedFunctionDataMap"),
("read_only_space", 0x052e9): (116, "WasmIndirectFunctionTableMap"),
("read_only_space", 0x05331): (117, "WasmJSFunctionDataMap"),
("read_only_space", 0x05379): (96, "InternalClassMap"),
("read_only_space", 0x053c1): (103, "SmiPairMap"),
("read_only_space", 0x05409): (102, "SmiBoxMap"),
("read_only_space", 0x05451): (104, "SortStateMap"),
("read_only_space", 0x05499): (85, "AllocationSiteWithWeakNextMap"),
("read_only_space", 0x054e1): (85, "AllocationSiteWithoutWeakNextMap"),
("read_only_space", 0x05529): (76, "LoadHandler1Map"),
("read_only_space", 0x05571): (76, "LoadHandler2Map"),
("read_only_space", 0x055b9): (76, "LoadHandler3Map"),
("read_only_space", 0x05601): (77, "StoreHandler0Map"),
("read_only_space", 0x05649): (77, "StoreHandler1Map"),
("read_only_space", 0x05691): (77, "StoreHandler2Map"),
("read_only_space", 0x056d9): (77, "StoreHandler3Map"),
("map_space", 0x00119): (1057, "ExternalMap"),
("map_space", 0x00161): (1072, "JSMessageObjectMap"),
("map_space", 0x00161): (1073, "JSMessageObjectMap"),
}
# List of known V8 objects.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment