blob: 5f744366cdec367490eabeab9b7149e11b6a813c [file] [log] [blame]
// Copyright 2017 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 <cmath>
#include <list>
#include <memory>
#include "src/builtins/builtins-utils-inl.h"
#include "src/builtins/builtins.h"
#include "src/date/date.h"
#include "src/logging/counters.h"
#include "src/objects/elements.h"
#include "src/objects/intl-objects.h"
#include "src/objects/js-array-inl.h"
#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-duration-format-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"
#include "src/objects/js-plural-rules-inl.h"
#include "src/objects/js-relative-time-format-inl.h"
#include "src/objects/js-segment-iterator-inl.h"
#include "src/objects/js-segmenter-inl.h"
#include "src/objects/js-segments-inl.h"
#include "src/objects/objects-inl.h"
#include "src/objects/option-utils.h"
#include "src/objects/property-descriptor.h"
#include "src/objects/smi.h"
#include "unicode/brkiter.h"
namespace v8 {
namespace internal {
BUILTIN(StringPrototypeToUpperCaseIntl) {
HandleScope scope(isolate);
TO_THIS_STRING(string, "String.prototype.toUpperCase");
string = String::Flatten(isolate, string);
RETURN_RESULT_OR_FAILURE(isolate, Intl::ConvertToUpper(isolate, string));
}
BUILTIN(StringPrototypeNormalizeIntl) {
HandleScope handle_scope(isolate);
isolate->CountUsage(v8::Isolate::UseCounterFeature::kStringNormalize);
TO_THIS_STRING(string, "String.prototype.normalize");
Handle<Object> form_input = args.atOrUndefined(isolate, 1);
RETURN_RESULT_OR_FAILURE(isolate,
Intl::Normalize(isolate, string, form_input));
}
BUILTIN(V8BreakIteratorSupportedLocalesOf) {
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.v8BreakIterator.supportedLocalesOf",
JSV8BreakIterator::GetAvailableLocales(), locales, options));
}
BUILTIN(NumberFormatSupportedLocalesOf) {
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.NumberFormat.supportedLocalesOf",
JSNumberFormat::GetAvailableLocales(), locales, options));
}
BUILTIN(NumberFormatPrototypeFormatToParts) {
const char* const method_name = "Intl.NumberFormat.prototype.formatToParts";
HandleScope handle_scope(isolate);
CHECK_RECEIVER(JSNumberFormat, number_format, method_name);
Handle<Object> x;
if (args.length() >= 2) {
x = args.at(1);
} else {
x = isolate->factory()->nan_value();
}
RETURN_RESULT_OR_FAILURE(
isolate, JSNumberFormat::FormatToParts(isolate, number_format, x));
}
BUILTIN(DateTimeFormatPrototypeResolvedOptions) {
const char* const method_name =
"Intl.DateTimeFormat.prototype.resolvedOptions";
HandleScope scope(isolate);
CHECK_RECEIVER(JSReceiver, format_holder, method_name);
// 3. Let dtf be ? UnwrapDateTimeFormat(dtf).
Handle<JSDateTimeFormat> date_time_format;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, date_time_format,
JSDateTimeFormat::UnwrapDateTimeFormat(isolate, format_holder));
RETURN_RESULT_OR_FAILURE(
isolate, JSDateTimeFormat::ResolvedOptions(isolate, date_time_format));
}
BUILTIN(DateTimeFormatSupportedLocalesOf) {
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.DateTimeFormat.supportedLocalesOf",
JSDateTimeFormat::GetAvailableLocales(), locales, options));
}
BUILTIN(DateTimeFormatPrototypeFormatToParts) {
const char* const method_name = "Intl.DateTimeFormat.prototype.formatToParts";
HandleScope handle_scope(isolate);
CHECK_RECEIVER(JSObject, date_format_holder, method_name);
Factory* factory = isolate->factory();
if (!IsJSDateTimeFormat(*date_format_holder)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
factory->NewStringFromAsciiChecked(method_name),
date_format_holder));
}
Handle<JSDateTimeFormat> dtf =
Handle<JSDateTimeFormat>::cast(date_format_holder);
Handle<Object> x = args.atOrUndefined(isolate, 1);
RETURN_RESULT_OR_FAILURE(isolate, JSDateTimeFormat::FormatToParts(
isolate, dtf, x, false, method_name));
}
// Common code for DateTimeFormatPrototypeFormtRange(|ToParts)
template <class T, MaybeHandle<T> (*F)(Isolate*, Handle<JSDateTimeFormat>,
Handle<Object>, Handle<Object>,
const char* const)>
V8_WARN_UNUSED_RESULT Tagged<Object> DateTimeFormatRange(
BuiltinArguments args, Isolate* isolate, const char* const method_name) {
// 1. Let dtf be this value.
// 2. Perform ? RequireInternalSlot(dtf, [[InitializedDateTimeFormat]]).
CHECK_RECEIVER(JSDateTimeFormat, dtf, method_name);
// 3. If startDate is undefined or endDate is undefined, throw a TypeError
// exception.
Handle<Object> start_date = args.atOrUndefined(isolate, 1);
Handle<Object> end_date = args.atOrUndefined(isolate, 2);
if (IsUndefined(*start_date, isolate) || IsUndefined(*end_date, isolate)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kInvalidTimeValue));
}
// 4. Return ? FormatDateTimeRange(dtf, startDate, endDate)
// OR
// 4. Return ? FormatDateTimeRangeToParts(dtf, startDate, endDate).
RETURN_RESULT_OR_FAILURE(isolate,
F(isolate, dtf, start_date, end_date, method_name));
}
BUILTIN(DateTimeFormatPrototypeFormatRange) {
const char* const method_name = "Intl.DateTimeFormat.prototype.formatRange";
HandleScope handle_scope(isolate);
return DateTimeFormatRange<String, JSDateTimeFormat::FormatRange>(
args, isolate, method_name);
}
BUILTIN(DateTimeFormatPrototypeFormatRangeToParts) {
const char* const method_name =
"Intl.DateTimeFormat.prototype.formatRangeToParts";
HandleScope handle_scope(isolate);
return DateTimeFormatRange<JSArray, JSDateTimeFormat::FormatRangeToParts>(
args, isolate, method_name);
}
namespace {
Handle<JSFunction> CreateBoundFunction(Isolate* isolate,
Handle<JSObject> object, Builtin builtin,
int len) {
Handle<NativeContext> native_context(isolate->context()->native_context(),
isolate);
Handle<Context> context = isolate->factory()->NewBuiltinContext(
native_context,
static_cast<int>(Intl::BoundFunctionContextSlot::kLength));
context->set(static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction),
*object);
Handle<SharedFunctionInfo> info =
isolate->factory()->NewSharedFunctionInfoForBuiltin(
isolate->factory()->empty_string(), builtin,
FunctionKind::kNormalFunction);
info->set_internal_formal_parameter_count(JSParameterCount(len));
info->set_length(len);
return Factory::JSFunctionBuilder{isolate, info, context}
.set_map(isolate->strict_function_without_prototype_map())
.Build();
}
/**
* Common code shared between DateTimeFormatConstructor and
* NumberFormatConstrutor
*/
template <class T>
Tagged<Object> LegacyFormatConstructor(BuiltinArguments args, Isolate* isolate,
v8::Isolate::UseCounterFeature feature,
Handle<Object> constructor,
const char* method_name) {
isolate->CountUsage(feature);
Handle<JSReceiver> new_target;
// 1. If NewTarget is undefined, let newTarget be the active
// function object, else let newTarget be NewTarget.
if (IsUndefined(*args.new_target(), isolate)) {
new_target = args.target();
} else {
new_target = Handle<JSReceiver>::cast(args.new_target());
}
// [[Construct]]
Handle<JSFunction> target = args.target();
Handle<Object> locales = args.atOrUndefined(isolate, 1);
Handle<Object> options = args.atOrUndefined(isolate, 2);
// 2. Let format be ? OrdinaryCreateFromConstructor(newTarget,
// "%<T>Prototype%", ...).
Handle<Map> map;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, map, JSFunction::GetDerivedMap(isolate, target, new_target));
// 3. Perform ? Initialize<T>(Format, locales, options).
Handle<T> format;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, format, T::New(isolate, map, locales, options, method_name));
// 4. Let this be the this value.
if (IsUndefined(*args.new_target(), isolate)) {
Handle<Object> receiver = args.receiver();
// 5. If NewTarget is undefined and ? OrdinaryHasInstance(%<T>%, this)
// is true, then Look up the intrinsic value that has been stored on
// the context.
Handle<Object> ordinary_has_instance_obj;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, ordinary_has_instance_obj,
Object::OrdinaryHasInstance(isolate, constructor, receiver));
if (Object::BooleanValue(*ordinary_has_instance_obj, isolate)) {
if (!IsJSReceiver(*receiver)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
isolate->factory()->NewStringFromAsciiChecked(
method_name),
receiver));
}
Handle<JSReceiver> rec = Handle<JSReceiver>::cast(receiver);
// a. Perform ? DefinePropertyOrThrow(this,
// %Intl%.[[FallbackSymbol]], PropertyDescriptor{ [[Value]]: format,
// [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }).
PropertyDescriptor desc;
desc.set_value(format);
desc.set_writable(false);
desc.set_enumerable(false);
desc.set_configurable(false);
Maybe<bool> success = JSReceiver::DefineOwnProperty(
isolate, rec, isolate->factory()->intl_fallback_symbol(), &desc,
Just(kThrowOnError));
MAYBE_RETURN(success, ReadOnlyRoots(isolate).exception());
CHECK(success.FromJust());
// b. b. Return this.
return *receiver;
}
}
// 6. Return format.
return *format;
}
/**
* Common code shared by ListFormat, RelativeTimeFormat, PluralRules, and
* Segmenter
*/
template <class T>
Tagged<Object> DisallowCallConstructor(BuiltinArguments args, Isolate* isolate,
v8::Isolate::UseCounterFeature feature,
const char* method_name) {
isolate->CountUsage(feature);
// 1. If NewTarget is undefined, throw a TypeError exception.
if (IsUndefined(*args.new_target(), isolate)) { // [[Call]]
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kConstructorNotFunction,
isolate->factory()->NewStringFromAsciiChecked(
method_name)));
}
// [[Construct]]
Handle<JSFunction> target = args.target();
Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target());
Handle<Map> map;
// 2. Let result be OrdinaryCreateFromConstructor(NewTarget,
// "%<T>Prototype%").
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, map, JSFunction::GetDerivedMap(isolate, target, new_target));
Handle<Object> locales = args.atOrUndefined(isolate, 1);
Handle<Object> options = args.atOrUndefined(isolate, 2);
// 3. Return New<T>(t, locales, options).
RETURN_RESULT_OR_FAILURE(isolate, T::New(isolate, map, locales, options));
}
/**
* Common code shared by Collator and V8BreakIterator
*/
template <class T>
Tagged<Object> CallOrConstructConstructor(BuiltinArguments args,
Isolate* isolate,
const char* method_name) {
Handle<JSReceiver> new_target;
if (IsUndefined(*args.new_target(), isolate)) {
new_target = args.target();
} else {
new_target = Handle<JSReceiver>::cast(args.new_target());
}
// [[Construct]]
Handle<JSFunction> target = args.target();
Handle<Object> locales = args.atOrUndefined(isolate, 1);
Handle<Object> options = args.atOrUndefined(isolate, 2);
Handle<Map> map;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, map, JSFunction::GetDerivedMap(isolate, target, new_target));
RETURN_RESULT_OR_FAILURE(isolate,
T::New(isolate, map, locales, options, method_name));
}
} // 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.DurationFormat
BUILTIN(DurationFormatConstructor) {
HandleScope scope(isolate);
return DisallowCallConstructor<JSDurationFormat>(
args, isolate, v8::Isolate::UseCounterFeature::kDurationFormat,
"Intl.DurationFormat");
}
BUILTIN(DurationFormatPrototypeResolvedOptions) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSDurationFormat, holder,
"Intl.DurationFormat.prototype.resolvedOptions");
return *JSDurationFormat::ResolvedOptions(isolate, holder);
}
BUILTIN(DurationFormatSupportedLocalesOf) {
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.DurationFormat.supportedLocalesOf",
JSDurationFormat::GetAvailableLocales(), locales, options));
}
BUILTIN(DurationFormatPrototypeFormat) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSDurationFormat, holder,
"Intl.DurationFormat.prototype.format");
Handle<Object> value = args.atOrUndefined(isolate, 1);
RETURN_RESULT_OR_FAILURE(isolate,
JSDurationFormat::Format(isolate, holder, value));
}
BUILTIN(DurationFormatPrototypeFormatToParts) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSDurationFormat, holder,
"Intl.DurationFormat.prototype.formatToParts");
Handle<Object> value = args.atOrUndefined(isolate, 1);
RETURN_RESULT_OR_FAILURE(
isolate, JSDurationFormat::FormatToParts(isolate, holder, value));
}
// Intl.NumberFormat
BUILTIN(NumberFormatConstructor) {
HandleScope scope(isolate);
return LegacyFormatConstructor<JSNumberFormat>(
args, isolate, v8::Isolate::UseCounterFeature::kNumberFormat,
isolate->intl_number_format_function(), "Intl.NumberFormat");
}
BUILTIN(NumberFormatPrototypeResolvedOptions) {
HandleScope scope(isolate);
const char* const method_name = "Intl.NumberFormat.prototype.resolvedOptions";
// 1. Let nf be the this value.
// 2. If Type(nf) is not Object, throw a TypeError exception.
CHECK_RECEIVER(JSReceiver, number_format_holder, method_name);
// 3. Let nf be ? UnwrapNumberFormat(nf)
Handle<JSNumberFormat> number_format;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, number_format,
JSNumberFormat::UnwrapNumberFormat(isolate, number_format_holder));
return *JSNumberFormat::ResolvedOptions(isolate, number_format);
}
BUILTIN(NumberFormatPrototypeFormatNumber) {
const char* const method_name = "get Intl.NumberFormat.prototype.format";
HandleScope scope(isolate);
// 1. Let nf be the this value.
// 2. If Type(nf) is not Object, throw a TypeError exception.
CHECK_RECEIVER(JSReceiver, receiver, method_name);
// 3. Let nf be ? UnwrapNumberFormat(nf).
Handle<JSNumberFormat> number_format;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, number_format,
JSNumberFormat::UnwrapNumberFormat(isolate, receiver));
Handle<Object> bound_format(number_format->bound_format(), isolate);
// 4. If nf.[[BoundFormat]] is undefined, then
if (!IsUndefined(*bound_format, isolate)) {
DCHECK(IsJSFunction(*bound_format));
// 5. Return nf.[[BoundFormat]].
return *bound_format;
}
Handle<JSFunction> new_bound_format_function = CreateBoundFunction(
isolate, number_format, Builtin::kNumberFormatInternalFormatNumber, 1);
// 4. c. Set nf.[[BoundFormat]] to F.
number_format->set_bound_format(*new_bound_format_function);
// 5. Return nf.[[BoundFormat]].
return *new_bound_format_function;
}
BUILTIN(NumberFormatInternalFormatNumber) {
HandleScope scope(isolate);
Handle<Context> context = Handle<Context>(isolate->context(), isolate);
// 1. Let nf be F.[[NumberFormat]].
// 2. Assert: Type(nf) is Object and nf has an
// [[InitializedNumberFormat]] internal slot.
Handle<JSNumberFormat> number_format = Handle<JSNumberFormat>(
JSNumberFormat::cast(context->get(
static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction))),
isolate);
// 3. If value is not provided, let value be undefined.
Handle<Object> value = args.atOrUndefined(isolate, 1);
RETURN_RESULT_OR_FAILURE(isolate, JSNumberFormat::NumberFormatFunction(
isolate, number_format, value));
}
// Common code for NumberFormatPrototypeFormtRange(|ToParts)
template <class T, MaybeHandle<T> (*F)(Isolate*, Handle<JSNumberFormat>,
Handle<Object>, Handle<Object>)>
V8_WARN_UNUSED_RESULT Tagged<Object> NumberFormatRange(
BuiltinArguments args, Isolate* isolate, const char* const method_name) {
// 1. Let nf be this value.
// 2. Perform ? RequireInternalSlot(nf, [[InitializedNumberFormat]]).
CHECK_RECEIVER(JSNumberFormat, nf, method_name);
Handle<Object> start = args.atOrUndefined(isolate, 1);
Handle<Object> end = args.atOrUndefined(isolate, 2);
Factory* factory = isolate->factory();
// 3. If start is undefined or end is undefined, throw a TypeError exception.
if (IsUndefined(*start, isolate)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate,
NewTypeError(MessageTemplate::kInvalid,
factory->NewStringFromStaticChars("start"), start));
}
if (IsUndefined(*end, isolate)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kInvalid,
factory->NewStringFromStaticChars("end"), end));
}
RETURN_RESULT_OR_FAILURE(isolate, F(isolate, nf, start, end));
}
BUILTIN(NumberFormatPrototypeFormatRange) {
const char* const method_name = "Intl.NumberFormat.prototype.formatRange";
HandleScope handle_scope(isolate);
return NumberFormatRange<String, JSNumberFormat::FormatNumericRange>(
args, isolate, method_name);
}
BUILTIN(NumberFormatPrototypeFormatRangeToParts) {
const char* const method_name =
"Intl.NumberFormat.prototype.formatRangeToParts";
HandleScope handle_scope(isolate);
return NumberFormatRange<JSArray, JSNumberFormat::FormatNumericRangeToParts>(
args, isolate, method_name);
}
BUILTIN(DateTimeFormatConstructor) {
HandleScope scope(isolate);
return LegacyFormatConstructor<JSDateTimeFormat>(
args, isolate, v8::Isolate::UseCounterFeature::kDateTimeFormat,
isolate->intl_date_time_format_function(), "Intl.DateTimeFormat");
}
BUILTIN(DateTimeFormatPrototypeFormat) {
const char* const method_name = "get Intl.DateTimeFormat.prototype.format";
HandleScope scope(isolate);
// 1. Let dtf be this value.
// 2. If Type(dtf) is not Object, throw a TypeError exception.
CHECK_RECEIVER(JSReceiver, receiver, method_name);
// 3. Let dtf be ? UnwrapDateTimeFormat(dtf).
Handle<JSDateTimeFormat> format;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, format,
JSDateTimeFormat::UnwrapDateTimeFormat(isolate, receiver));
Handle<Object> bound_format = Handle<Object>(format->bound_format(), isolate);
// 4. If dtf.[[BoundFormat]] is undefined, then
if (!IsUndefined(*bound_format, isolate)) {
DCHECK(IsJSFunction(*bound_format));
// 5. Return dtf.[[BoundFormat]].
return *bound_format;
}
Handle<JSFunction> new_bound_format_function = CreateBoundFunction(
isolate, format, Builtin::kDateTimeFormatInternalFormat, 1);
// 4.c. Set dtf.[[BoundFormat]] to F.
format->set_bound_format(*new_bound_format_function);
// 5. Return dtf.[[BoundFormat]].
return *new_bound_format_function;
}
BUILTIN(DateTimeFormatInternalFormat) {
HandleScope scope(isolate);
Handle<Context> context = Handle<Context>(isolate->context(), isolate);
// 1. Let dtf be F.[[DateTimeFormat]].
// 2. Assert: Type(dtf) is Object and dtf has an [[InitializedDateTimeFormat]]
// internal slot.
Handle<JSDateTimeFormat> date_format_holder = Handle<JSDateTimeFormat>(
JSDateTimeFormat::cast(context->get(
static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction))),
isolate);
Handle<Object> date = args.atOrUndefined(isolate, 1);
RETURN_RESULT_OR_FAILURE(isolate, JSDateTimeFormat::DateTimeFormat(
isolate, date_format_holder, date,
"DateTime Format Functions"));
}
BUILTIN(IntlGetCanonicalLocales) {
HandleScope scope(isolate);
Handle<Object> locales = args.atOrUndefined(isolate, 1);
RETURN_RESULT_OR_FAILURE(isolate,
Intl::GetCanonicalLocales(isolate, locales));
}
BUILTIN(IntlSupportedValuesOf) {
HandleScope scope(isolate);
Handle<Object> locales = args.atOrUndefined(isolate, 1);
RETURN_RESULT_OR_FAILURE(isolate, Intl::SupportedValuesOf(isolate, locales));
}
BUILTIN(ListFormatConstructor) {
HandleScope scope(isolate);
return DisallowCallConstructor<JSListFormat>(
args, isolate, v8::Isolate::UseCounterFeature::kListFormat,
"Intl.ListFormat");
}
BUILTIN(ListFormatPrototypeResolvedOptions) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSListFormat, format_holder,
"Intl.ListFormat.prototype.resolvedOptions");
return *JSListFormat::ResolvedOptions(isolate, format_holder);
}
BUILTIN(ListFormatSupportedLocalesOf) {
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.ListFormat.supportedLocalesOf",
JSListFormat::GetAvailableLocales(), locales, options));
}
// Intl.Locale implementation
BUILTIN(LocaleConstructor) {
HandleScope scope(isolate);
isolate->CountUsage(v8::Isolate::UseCounterFeature::kLocale);
const char* method_name = "Intl.Locale";
if (IsUndefined(*args.new_target(), isolate)) { // [[Call]]
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kConstructorNotFunction,
isolate->factory()->NewStringFromAsciiChecked(
method_name)));
}
// [[Construct]]
Handle<JSFunction> target = args.target();
Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target());
Handle<Object> tag = args.atOrUndefined(isolate, 1);
Handle<Object> options = args.atOrUndefined(isolate, 2);
Handle<Map> map;
// 6. Let locale be ? OrdinaryCreateFromConstructor(NewTarget,
// %LocalePrototype%, internalSlotsList).
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, map, JSFunction::GetDerivedMap(isolate, target, new_target));
// 7. If Type(tag) is not String or Object, throw a TypeError exception.
if (!IsString(*tag) && !IsJSReceiver(*tag)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kLocaleNotEmpty));
}
Handle<String> locale_string;
// 8. If Type(tag) is Object and tag has an [[InitializedLocale]] internal
// slot, then
if (IsJSLocale(*tag)) {
// a. Let tag be tag.[[Locale]].
locale_string = JSLocale::ToString(isolate, Handle<JSLocale>::cast(tag));
} else { // 9. Else,
// a. Let tag be ? ToString(tag).
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, locale_string,
Object::ToString(isolate, tag));
}
// 10. Set options to ? CoerceOptionsToObject(options).
Handle<JSReceiver> options_object;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, options_object,
CoerceOptionsToObject(isolate, options, method_name));
RETURN_RESULT_OR_FAILURE(
isolate, JSLocale::New(isolate, map, locale_string, options_object));
}
BUILTIN(LocalePrototypeMaximize) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.maximize");
RETURN_RESULT_OR_FAILURE(isolate, JSLocale::Maximize(isolate, locale));
}
BUILTIN(LocalePrototypeMinimize) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.minimize");
RETURN_RESULT_OR_FAILURE(isolate, JSLocale::Minimize(isolate, locale));
}
BUILTIN(LocalePrototypeGetCalendars) {
HandleScope scope(isolate);
isolate->CountUsage(v8::Isolate::UseCounterFeature::kLocaleInfoFunctions);
CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.getCalendars");
RETURN_RESULT_OR_FAILURE(isolate, JSLocale::GetCalendars(isolate, locale));
}
BUILTIN(LocalePrototypeGetCollations) {
HandleScope scope(isolate);
isolate->CountUsage(v8::Isolate::UseCounterFeature::kLocaleInfoFunctions);
CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.getCollations");
RETURN_RESULT_OR_FAILURE(isolate, JSLocale::GetCollations(isolate, locale));
}
BUILTIN(LocalePrototypeGetHourCycles) {
HandleScope scope(isolate);
isolate->CountUsage(v8::Isolate::UseCounterFeature::kLocaleInfoFunctions);
CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.getHourCycles");
RETURN_RESULT_OR_FAILURE(isolate, JSLocale::GetHourCycles(isolate, locale));
}
BUILTIN(LocalePrototypeGetNumberingSystems) {
HandleScope scope(isolate);
isolate->CountUsage(v8::Isolate::UseCounterFeature::kLocaleInfoFunctions);
CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.getNumberingSystems");
RETURN_RESULT_OR_FAILURE(isolate,
JSLocale::GetNumberingSystems(isolate, locale));
}
BUILTIN(LocalePrototypeGetTextInfo) {
HandleScope scope(isolate);
isolate->CountUsage(v8::Isolate::UseCounterFeature::kLocaleInfoFunctions);
CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.getTextInfo");
RETURN_RESULT_OR_FAILURE(isolate, JSLocale::GetTextInfo(isolate, locale));
}
BUILTIN(LocalePrototypeGetTimeZones) {
HandleScope scope(isolate);
isolate->CountUsage(v8::Isolate::UseCounterFeature::kLocaleInfoFunctions);
CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.getTimeZones");
RETURN_RESULT_OR_FAILURE(isolate, JSLocale::GetTimeZones(isolate, locale));
}
BUILTIN(LocalePrototypeGetWeekInfo) {
HandleScope scope(isolate);
isolate->CountUsage(v8::Isolate::UseCounterFeature::kLocaleInfoFunctions);
CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.getWeekInfo");
RETURN_RESULT_OR_FAILURE(isolate, JSLocale::GetWeekInfo(isolate, locale));
}
BUILTIN(LocalePrototypeCalendars) {
HandleScope scope(isolate);
isolate->CountUsage(
v8::Isolate::UseCounterFeature::kLocaleInfoObsoletedGetters);
CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.calendars");
RETURN_RESULT_OR_FAILURE(isolate, JSLocale::GetCalendars(isolate, locale));
}
BUILTIN(LocalePrototypeCollations) {
HandleScope scope(isolate);
isolate->CountUsage(
v8::Isolate::UseCounterFeature::kLocaleInfoObsoletedGetters);
CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.collations");
RETURN_RESULT_OR_FAILURE(isolate, JSLocale::GetCollations(isolate, locale));
}
BUILTIN(LocalePrototypeHourCycles) {
HandleScope scope(isolate);
isolate->CountUsage(
v8::Isolate::UseCounterFeature::kLocaleInfoObsoletedGetters);
CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.hourCycles");
RETURN_RESULT_OR_FAILURE(isolate, JSLocale::GetHourCycles(isolate, locale));
}
BUILTIN(LocalePrototypeNumberingSystems) {
HandleScope scope(isolate);
isolate->CountUsage(
v8::Isolate::UseCounterFeature::kLocaleInfoObsoletedGetters);
CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.numberingSystems");
RETURN_RESULT_OR_FAILURE(isolate,
JSLocale::GetNumberingSystems(isolate, locale));
}
BUILTIN(LocalePrototypeTextInfo) {
HandleScope scope(isolate);
isolate->CountUsage(
v8::Isolate::UseCounterFeature::kLocaleInfoObsoletedGetters);
CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.textInfo");
RETURN_RESULT_OR_FAILURE(isolate, JSLocale::GetTextInfo(isolate, locale));
}
BUILTIN(LocalePrototypeTimeZones) {
HandleScope scope(isolate);
isolate->CountUsage(
v8::Isolate::UseCounterFeature::kLocaleInfoObsoletedGetters);
CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.timeZones");
RETURN_RESULT_OR_FAILURE(isolate, JSLocale::GetTimeZones(isolate, locale));
}
BUILTIN(LocalePrototypeWeekInfo) {
HandleScope scope(isolate);
isolate->CountUsage(
v8::Isolate::UseCounterFeature::kLocaleInfoObsoletedGetters);
CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.weekInfo");
RETURN_RESULT_OR_FAILURE(isolate, JSLocale::GetWeekInfo(isolate, locale));
}
BUILTIN(RelativeTimeFormatSupportedLocalesOf) {
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.RelativeTimeFormat.supportedLocalesOf",
JSRelativeTimeFormat::GetAvailableLocales(), locales, options));
}
BUILTIN(RelativeTimeFormatPrototypeFormat) {
HandleScope scope(isolate);
// 1. Let relativeTimeFormat be the this value.
// 2. If Type(relativeTimeFormat) is not Object or relativeTimeFormat does not
// have an [[InitializedRelativeTimeFormat]] internal slot whose value is
// true, throw a TypeError exception.
CHECK_RECEIVER(JSRelativeTimeFormat, format_holder,
"Intl.RelativeTimeFormat.prototype.format");
Handle<Object> value_obj = args.atOrUndefined(isolate, 1);
Handle<Object> unit_obj = args.atOrUndefined(isolate, 2);
RETURN_RESULT_OR_FAILURE(
isolate, JSRelativeTimeFormat::Format(isolate, value_obj, unit_obj,
format_holder));
}
BUILTIN(RelativeTimeFormatPrototypeFormatToParts) {
HandleScope scope(isolate);
// 1. Let relativeTimeFormat be the this value.
// 2. If Type(relativeTimeFormat) is not Object or relativeTimeFormat does not
// have an [[InitializedRelativeTimeFormat]] internal slot whose value is
// true, throw a TypeError exception.
CHECK_RECEIVER(JSRelativeTimeFormat, format_holder,
"Intl.RelativeTimeFormat.prototype.formatToParts");
Handle<Object> value_obj = args.atOrUndefined(isolate, 1);
Handle<Object> unit_obj = args.atOrUndefined(isolate, 2);
RETURN_RESULT_OR_FAILURE(
isolate, JSRelativeTimeFormat::FormatToParts(isolate, value_obj, unit_obj,
format_holder));
}
// Locale getters.
BUILTIN(LocalePrototypeLanguage) {
HandleScope scope(isolate);
// CHECK_RECEIVER will case locale_holder to JSLocale.
CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.language");
return *JSLocale::Language(isolate, locale);
}
BUILTIN(LocalePrototypeScript) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.script");
return *JSLocale::Script(isolate, locale);
}
BUILTIN(LocalePrototypeRegion) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.region");
return *JSLocale::Region(isolate, locale);
}
BUILTIN(LocalePrototypeBaseName) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.baseName");
return *JSLocale::BaseName(isolate, locale);
}
BUILTIN(LocalePrototypeCalendar) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.calendar");
return *JSLocale::Calendar(isolate, locale);
}
BUILTIN(LocalePrototypeCaseFirst) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.caseFirst");
return *JSLocale::CaseFirst(isolate, locale);
}
BUILTIN(LocalePrototypeCollation) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.collation");
return *JSLocale::Collation(isolate, locale);
}
BUILTIN(LocalePrototypeHourCycle) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.hourCycle");
return *JSLocale::HourCycle(isolate, locale);
}
BUILTIN(LocalePrototypeNumeric) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.numeric");
return *JSLocale::Numeric(isolate, locale);
}
BUILTIN(LocalePrototypeNumberingSystem) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.numberingSystem");
return *JSLocale::NumberingSystem(isolate, locale);
}
BUILTIN(LocalePrototypeToString) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSLocale, locale, "Intl.Locale.prototype.toString");
return *JSLocale::ToString(isolate, locale);
}
BUILTIN(RelativeTimeFormatConstructor) {
HandleScope scope(isolate);
return DisallowCallConstructor<JSRelativeTimeFormat>(
args, isolate, v8::Isolate::UseCounterFeature::kRelativeTimeFormat,
"Intl.RelativeTimeFormat");
}
BUILTIN(RelativeTimeFormatPrototypeResolvedOptions) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSRelativeTimeFormat, format_holder,
"Intl.RelativeTimeFormat.prototype.resolvedOptions");
return *JSRelativeTimeFormat::ResolvedOptions(isolate, format_holder);
}
bool IsFastLocale(Tagged<Object> maybe_locale) {
DisallowGarbageCollection no_gc;
if (!IsSeqOneByteString(maybe_locale)) {
return false;
}
auto locale = SeqOneByteString::cast(maybe_locale);
uint8_t* chars = locale->GetChars(no_gc);
if (locale->length() < 2 || !std::isalpha(chars[0]) ||
!std::isalpha(chars[1])) {
return false;
}
if (locale->length() != 2 &&
(locale->length() != 5 || chars[2] != '-' || !std::isalpha(chars[3]) ||
!std::isalpha(chars[4]))) {
return false;
}
char first = chars[0] | 0x20;
char second = chars[1] | 0x20;
return (first != 'a' || second != 'z') && (first != 'e' || second != 'l') &&
(first != 'l' || second != 't') && (first != 't' || second != 'r');
}
BUILTIN(StringPrototypeToLocaleUpperCase) {
HandleScope scope(isolate);
Handle<Object> maybe_locale = args.atOrUndefined(isolate, 1);
TO_THIS_STRING(string, "String.prototype.toLocaleUpperCase");
if (IsUndefined(*maybe_locale) || IsFastLocale(*maybe_locale)) {
string = String::Flatten(isolate, string);
RETURN_RESULT_OR_FAILURE(isolate, Intl::ConvertToUpper(isolate, string));
} else {
RETURN_RESULT_OR_FAILURE(isolate, Intl::StringLocaleConvertCase(
isolate, string, true, maybe_locale));
}
}
BUILTIN(PluralRulesConstructor) {
HandleScope scope(isolate);
return DisallowCallConstructor<JSPluralRules>(
args, isolate, v8::Isolate::UseCounterFeature::kPluralRules,
"Intl.PluralRules");
}
BUILTIN(PluralRulesPrototypeResolvedOptions) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSPluralRules, plural_rules_holder,
"Intl.PluralRules.prototype.resolvedOptions");
return *JSPluralRules::ResolvedOptions(isolate, plural_rules_holder);
}
BUILTIN(PluralRulesPrototypeSelect) {
HandleScope scope(isolate);
// 1. 1. Let pr be the this value.
// 2. Perform ? RequireInternalSlot(pr, [[InitializedPluralRules]]).
CHECK_RECEIVER(JSPluralRules, plural_rules,
"Intl.PluralRules.prototype.select");
// 3. Let n be ? ToNumber(value).
Handle<Object> number = args.atOrUndefined(isolate, 1);
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, number,
Object::ToNumber(isolate, number));
double number_double = Object::Number(*number);
// 4. Return ! ResolvePlural(pr, n).
RETURN_RESULT_OR_FAILURE(isolate, JSPluralRules::ResolvePlural(
isolate, plural_rules, number_double));
}
BUILTIN(PluralRulesPrototypeSelectRange) {
HandleScope scope(isolate);
// 1. Let pr be the this value.
// 2. Perform ? RequireInternalSlot(pr, [[InitializedPluralRules]]).
CHECK_RECEIVER(JSPluralRules, plural_rules,
"Intl.PluralRules.prototype.selectRange");
// 3. If start is undefined or end is undefined, throw a TypeError exception.
Handle<Object> start = args.atOrUndefined(isolate, 1);
Handle<Object> end = args.atOrUndefined(isolate, 2);
if (IsUndefined(*start)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kInvalid,
isolate->factory()->startRange_string(), start));
}
if (IsUndefined(*end)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kInvalid,
isolate->factory()->endRange_string(), end));
}
// 4. Let x be ? ToNumber(start).
Handle<Object> x;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, x,
Object::ToNumber(isolate, start));
// 5. Let y be ? ToNumber(end).
Handle<Object> y;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, y,
Object::ToNumber(isolate, end));
// 6. Return ! ResolvePluralRange(pr, x, y).
if (IsNaN(*x)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewRangeError(MessageTemplate::kInvalid,
isolate->factory()->startRange_string(), x));
}
if (IsNaN(*y)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewRangeError(MessageTemplate::kInvalid,
isolate->factory()->endRange_string(), y));
}
RETURN_RESULT_OR_FAILURE(
isolate,
JSPluralRules::ResolvePluralRange(
isolate, plural_rules, Object::Number(*x), Object::Number(*y)));
}
BUILTIN(PluralRulesSupportedLocalesOf) {
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.PluralRules.supportedLocalesOf",
JSPluralRules::GetAvailableLocales(), locales, options));
}
BUILTIN(CollatorConstructor) {
HandleScope scope(isolate);
isolate->CountUsage(v8::Isolate::UseCounterFeature::kCollator);
return CallOrConstructConstructor<JSCollator>(args, isolate, "Intl.Collator");
}
BUILTIN(CollatorPrototypeResolvedOptions) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSCollator, collator_holder,
"Intl.Collator.prototype.resolvedOptions");
return *JSCollator::ResolvedOptions(isolate, collator_holder);
}
BUILTIN(CollatorSupportedLocalesOf) {
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.Collator.supportedLocalesOf",
JSCollator::GetAvailableLocales(), locales, options));
}
BUILTIN(CollatorPrototypeCompare) {
const char* const method_name = "get Intl.Collator.prototype.compare";
HandleScope scope(isolate);
// 1. Let collator be this value.
// 2. If Type(collator) is not Object, throw a TypeError exception.
// 3. If collator does not have an [[InitializedCollator]] internal slot,
// throw a TypeError exception.
CHECK_RECEIVER(JSCollator, collator, method_name);
// 4. If collator.[[BoundCompare]] is undefined, then
Handle<Object> bound_compare(collator->bound_compare(), isolate);
if (!IsUndefined(*bound_compare, isolate)) {
DCHECK(IsJSFunction(*bound_compare));
// 5. Return collator.[[BoundCompare]].
return *bound_compare;
}
Handle<JSFunction> new_bound_compare_function = CreateBoundFunction(
isolate, collator, Builtin::kCollatorInternalCompare, 2);
// 4.c. Set collator.[[BoundCompare]] to F.
collator->set_bound_compare(*new_bound_compare_function);
// 5. Return collator.[[BoundCompare]].
return *new_bound_compare_function;
}
BUILTIN(CollatorInternalCompare) {
HandleScope scope(isolate);
Handle<Context> context = Handle<Context>(isolate->context(), isolate);
// 1. Let collator be F.[[Collator]].
// 2. Assert: Type(collator) is Object and collator has an
// [[InitializedCollator]] internal slot.
Handle<JSCollator> collator = Handle<JSCollator>(
JSCollator::cast(context->get(
static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction))),
isolate);
// 3. If x is not provided, let x be undefined.
Handle<Object> x = args.atOrUndefined(isolate, 1);
// 4. If y is not provided, let y be undefined.
Handle<Object> y = args.atOrUndefined(isolate, 2);
// 5. Let X be ? ToString(x).
Handle<String> string_x;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, string_x,
Object::ToString(isolate, x));
// 6. Let Y be ? ToString(y).
Handle<String> string_y;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, string_y,
Object::ToString(isolate, y));
// 7. Return CompareStrings(collator, X, Y).
icu::Collator* icu_collator = collator->icu_collator()->raw();
CHECK_NOT_NULL(icu_collator);
return Smi::FromInt(
Intl::CompareStrings(isolate, *icu_collator, string_x, string_y));
}
// ecma402 #sec-%segmentiteratorprototype%.next
BUILTIN(SegmentIteratorPrototypeNext) {
const char* const method_name = "%SegmentIterator.prototype%.next";
HandleScope scope(isolate);
CHECK_RECEIVER(JSSegmentIterator, segment_iterator, method_name);
RETURN_RESULT_OR_FAILURE(isolate,
JSSegmentIterator::Next(isolate, segment_iterator));
}
// ecma402 #sec-intl.segmenter
BUILTIN(SegmenterConstructor) {
HandleScope scope(isolate);
return DisallowCallConstructor<JSSegmenter>(
args, isolate, v8::Isolate::UseCounterFeature::kSegmenter,
"Intl.Segmenter");
}
// ecma402 #sec-intl.segmenter.supportedlocalesof
BUILTIN(SegmenterSupportedLocalesOf) {
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.Segmenter.supportedLocalesOf",
JSSegmenter::GetAvailableLocales(), locales, options));
}
// ecma402 #sec-intl.segmenter.prototype.resolvedoptions
BUILTIN(SegmenterPrototypeResolvedOptions) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSSegmenter, segmenter,
"Intl.Segmenter.prototype.resolvedOptions");
return *JSSegmenter::ResolvedOptions(isolate, segmenter);
}
// ecma402 #sec-intl.segmenter.prototype.segment
BUILTIN(SegmenterPrototypeSegment) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSSegmenter, segmenter, "Intl.Segmenter.prototype.segment");
Handle<Object> input_text = args.atOrUndefined(isolate, 1);
// 3. Let string be ? ToString(string).
Handle<String> string;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, string,
Object::ToString(isolate, input_text));
// 4. Return ? CreateSegmentsObject(segmenter, string).
RETURN_RESULT_OR_FAILURE(isolate,
JSSegments::Create(isolate, segmenter, string));
}
// ecma402 #sec-%segmentsprototype%.containing
BUILTIN(SegmentsPrototypeContaining) {
const char* const method_name = "%Segments.prototype%.containing";
HandleScope scope(isolate);
CHECK_RECEIVER(JSSegments, segments, method_name);
Handle<Object> index = args.atOrUndefined(isolate, 1);
// 6. Let n be ? ToInteger(index).
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, index,
Object::ToInteger(isolate, index));
double const n = Object::Number(*index);
RETURN_RESULT_OR_FAILURE(isolate,
JSSegments::Containing(isolate, segments, n));
}
// ecma402 #sec-%segmentsprototype%-@@iterator
BUILTIN(SegmentsPrototypeIterator) {
const char* const method_name = "%SegmentIsPrototype%[@@iterator]";
HandleScope scope(isolate);
CHECK_RECEIVER(JSSegments, segments, method_name);
RETURN_RESULT_OR_FAILURE(
isolate,
JSSegmentIterator::Create(
isolate, handle(segments->raw_string(), isolate),
segments->icu_break_iterator()->raw(), segments->granularity()));
}
BUILTIN(V8BreakIteratorConstructor) {
HandleScope scope(isolate);
return CallOrConstructConstructor<JSV8BreakIterator>(args, isolate,
"Intl.v8BreakIterator");
}
BUILTIN(V8BreakIteratorPrototypeResolvedOptions) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSV8BreakIterator, break_iterator,
"Intl.v8BreakIterator.prototype.resolvedOptions");
return *JSV8BreakIterator::ResolvedOptions(isolate, break_iterator);
}
BUILTIN(V8BreakIteratorPrototypeAdoptText) {
const char* const method_name =
"get Intl.v8BreakIterator.prototype.adoptText";
HandleScope scope(isolate);
CHECK_RECEIVER(JSV8BreakIterator, break_iterator, method_name);
Handle<Object> bound_adopt_text(break_iterator->bound_adopt_text(), isolate);
if (!IsUndefined(*bound_adopt_text, isolate)) {
DCHECK(IsJSFunction(*bound_adopt_text));
return *bound_adopt_text;
}
Handle<JSFunction> new_bound_adopt_text_function = CreateBoundFunction(
isolate, break_iterator, Builtin::kV8BreakIteratorInternalAdoptText, 1);
break_iterator->set_bound_adopt_text(*new_bound_adopt_text_function);
return *new_bound_adopt_text_function;
}
BUILTIN(V8BreakIteratorInternalAdoptText) {
HandleScope scope(isolate);
Handle<Context> context = Handle<Context>(isolate->context(), isolate);
Handle<JSV8BreakIterator> break_iterator = Handle<JSV8BreakIterator>(
JSV8BreakIterator::cast(context->get(
static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction))),
isolate);
Handle<Object> input_text = args.atOrUndefined(isolate, 1);
Handle<String> text;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, text,
Object::ToString(isolate, input_text));
JSV8BreakIterator::AdoptText(isolate, break_iterator, text);
return ReadOnlyRoots(isolate).undefined_value();
}
BUILTIN(V8BreakIteratorPrototypeFirst) {
const char* const method_name = "get Intl.v8BreakIterator.prototype.first";
HandleScope scope(isolate);
CHECK_RECEIVER(JSV8BreakIterator, break_iterator, method_name);
Handle<Object> bound_first(break_iterator->bound_first(), isolate);
if (!IsUndefined(*bound_first, isolate)) {
DCHECK(IsJSFunction(*bound_first));
return *bound_first;
}
Handle<JSFunction> new_bound_first_function = CreateBoundFunction(
isolate, break_iterator, Builtin::kV8BreakIteratorInternalFirst, 0);
break_iterator->set_bound_first(*new_bound_first_function);
return *new_bound_first_function;
}
BUILTIN(V8BreakIteratorInternalFirst) {
HandleScope scope(isolate);
Handle<Context> context = Handle<Context>(isolate->context(), isolate);
Handle<JSV8BreakIterator> break_iterator = Handle<JSV8BreakIterator>(
JSV8BreakIterator::cast(context->get(
static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction))),
isolate);
return *JSV8BreakIterator::First(isolate, break_iterator);
}
BUILTIN(V8BreakIteratorPrototypeNext) {
const char* const method_name = "get Intl.v8BreakIterator.prototype.next";
HandleScope scope(isolate);
CHECK_RECEIVER(JSV8BreakIterator, break_iterator, method_name);
Handle<Object> bound_next(break_iterator->bound_next(), isolate);
if (!IsUndefined(*bound_next, isolate)) {
DCHECK(IsJSFunction(*bound_next));
return *bound_next;
}
Handle<JSFunction> new_bound_next_function = CreateBoundFunction(
isolate, break_iterator, Builtin::kV8BreakIteratorInternalNext, 0);
break_iterator->set_bound_next(*new_bound_next_function);
return *new_bound_next_function;
}
BUILTIN(V8BreakIteratorInternalNext) {
HandleScope scope(isolate);
Handle<Context> context = Handle<Context>(isolate->context(), isolate);
Handle<JSV8BreakIterator> break_iterator = Handle<JSV8BreakIterator>(
JSV8BreakIterator::cast(context->get(
static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction))),
isolate);
return *JSV8BreakIterator::Next(isolate, break_iterator);
}
BUILTIN(V8BreakIteratorPrototypeCurrent) {
const char* const method_name = "get Intl.v8BreakIterator.prototype.current";
HandleScope scope(isolate);
CHECK_RECEIVER(JSV8BreakIterator, break_iterator, method_name);
Handle<Object> bound_current(break_iterator->bound_current(), isolate);
if (!IsUndefined(*bound_current, isolate)) {
DCHECK(IsJSFunction(*bound_current));
return *bound_current;
}
Handle<JSFunction> new_bound_current_function = CreateBoundFunction(
isolate, break_iterator, Builtin::kV8BreakIteratorInternalCurrent, 0);
break_iterator->set_bound_current(*new_bound_current_function);
return *new_bound_current_function;
}
BUILTIN(V8BreakIteratorInternalCurrent) {
HandleScope scope(isolate);
Handle<Context> context = Handle<Context>(isolate->context(), isolate);
Handle<JSV8BreakIterator> break_iterator = Handle<JSV8BreakIterator>(
JSV8BreakIterator::cast(context->get(
static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction))),
isolate);
return *JSV8BreakIterator::Current(isolate, break_iterator);
}
BUILTIN(V8BreakIteratorPrototypeBreakType) {
const char* const method_name =
"get Intl.v8BreakIterator.prototype.breakType";
HandleScope scope(isolate);
CHECK_RECEIVER(JSV8BreakIterator, break_iterator, method_name);
Handle<Object> bound_break_type(break_iterator->bound_break_type(), isolate);
if (!IsUndefined(*bound_break_type, isolate)) {
DCHECK(IsJSFunction(*bound_break_type));
return *bound_break_type;
}
Handle<JSFunction> new_bound_break_type_function = CreateBoundFunction(
isolate, break_iterator, Builtin::kV8BreakIteratorInternalBreakType, 0);
break_iterator->set_bound_break_type(*new_bound_break_type_function);
return *new_bound_break_type_function;
}
BUILTIN(V8BreakIteratorInternalBreakType) {
HandleScope scope(isolate);
Handle<Context> context = Handle<Context>(isolate->context(), isolate);
Handle<JSV8BreakIterator> break_iterator = Handle<JSV8BreakIterator>(
JSV8BreakIterator::cast(context->get(
static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction))),
isolate);
return JSV8BreakIterator::BreakType(isolate, break_iterator);
}
} // namespace internal
} // namespace v8