| // 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.h" |
| #include "src/elements.h" |
| #include "src/intl.h" |
| #include "src/objects-inl.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-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/property-descriptor.h" |
| |
| #include "unicode/datefmt.h" |
| #include "unicode/decimfmt.h" |
| #include "unicode/fieldpos.h" |
| #include "unicode/fpositer.h" |
| #include "unicode/listformatter.h" |
| #include "unicode/normalizer2.h" |
| #include "unicode/numfmt.h" |
| #include "unicode/smpdtfmt.h" |
| #include "unicode/udat.h" |
| #include "unicode/ufieldpositer.h" |
| #include "unicode/unistr.h" |
| #include "unicode/ustring.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, ConvertCase(string, true, isolate)); |
| } |
| |
| BUILTIN(StringPrototypeNormalizeIntl) { |
| HandleScope handle_scope(isolate); |
| TO_THIS_STRING(string, "String.prototype.normalize"); |
| |
| Handle<Object> form_input = args.atOrUndefined(isolate, 1); |
| const char* form_name; |
| UNormalization2Mode form_mode; |
| if (form_input->IsUndefined(isolate)) { |
| // default is FNC |
| form_name = "nfc"; |
| form_mode = UNORM2_COMPOSE; |
| } else { |
| Handle<String> form; |
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, form, |
| Object::ToString(isolate, form_input)); |
| |
| if (String::Equals(isolate, form, isolate->factory()->NFC_string())) { |
| form_name = "nfc"; |
| form_mode = UNORM2_COMPOSE; |
| } else if (String::Equals(isolate, form, |
| isolate->factory()->NFD_string())) { |
| form_name = "nfc"; |
| form_mode = UNORM2_DECOMPOSE; |
| } else if (String::Equals(isolate, form, |
| isolate->factory()->NFKC_string())) { |
| form_name = "nfkc"; |
| form_mode = UNORM2_COMPOSE; |
| } else if (String::Equals(isolate, form, |
| isolate->factory()->NFKD_string())) { |
| form_name = "nfkc"; |
| form_mode = UNORM2_DECOMPOSE; |
| } else { |
| Handle<String> valid_forms = |
| isolate->factory()->NewStringFromStaticChars("NFC, NFD, NFKC, NFKD"); |
| THROW_NEW_ERROR_RETURN_FAILURE( |
| isolate, |
| NewRangeError(MessageTemplate::kNormalizationForm, valid_forms)); |
| } |
| } |
| |
| int length = string->length(); |
| string = String::Flatten(isolate, string); |
| icu::UnicodeString result; |
| std::unique_ptr<uc16[]> sap; |
| UErrorCode status = U_ZERO_ERROR; |
| { |
| DisallowHeapAllocation no_gc; |
| String::FlatContent flat = string->GetFlatContent(); |
| const UChar* src = GetUCharBufferFromFlat(flat, &sap, length); |
| icu::UnicodeString input(false, src, length); |
| // Getting a singleton. Should not free it. |
| const icu::Normalizer2* normalizer = |
| icu::Normalizer2::getInstance(nullptr, form_name, form_mode, status); |
| DCHECK(U_SUCCESS(status)); |
| CHECK_NOT_NULL(normalizer); |
| int32_t normalized_prefix_length = |
| normalizer->spanQuickCheckYes(input, status); |
| // Quick return if the input is already normalized. |
| if (length == normalized_prefix_length) return *string; |
| icu::UnicodeString unnormalized = |
| input.tempSubString(normalized_prefix_length); |
| // Read-only alias of the normalized prefix. |
| result.setTo(false, input.getBuffer(), normalized_prefix_length); |
| // copy-on-write; normalize the suffix and append to |result|. |
| normalizer->normalizeSecondAndAppend(result, unnormalized, status); |
| } |
| |
| if (U_FAILURE(status)) { |
| THROW_NEW_ERROR_RETURN_FAILURE(isolate, |
| NewTypeError(MessageTemplate::kIcuError)); |
| } |
| |
| RETURN_RESULT_OR_FAILURE( |
| isolate, isolate->factory()->NewStringFromTwoByte(Vector<const uint16_t>( |
| reinterpret_cast<const uint16_t*>(result.getBuffer()), |
| result.length()))); |
| } |
| |
| namespace { |
| |
| MaybeHandle<JSObject> SupportedLocalesOfCommon(Isolate* isolate, |
| const char* service_in, |
| BuiltinArguments args) { |
| Factory* factory = isolate->factory(); |
| Handle<String> service = factory->NewStringFromAsciiChecked(service_in); |
| Handle<Object> locales = args.atOrUndefined(isolate, 1); |
| Handle<Object> options = args.atOrUndefined(isolate, 2); |
| |
| MaybeHandle<JSObject> result = |
| Intl::SupportedLocalesOf(isolate, service, locales, options); |
| Handle<JSObject> elements; |
| ASSIGN_RETURN_ON_EXCEPTION(isolate, elements, result, JSObject); |
| return elements; |
| } |
| |
| } // namespace |
| |
| BUILTIN(V8BreakIteratorSupportedLocalesOf) { |
| HandleScope scope(isolate); |
| // 1. If NewTarget is defined, throw a TypeError exception. |
| if (!args.new_target()->IsUndefined(isolate)) { // [[Call]] |
| THROW_NEW_ERROR_RETURN_FAILURE( |
| isolate, |
| NewTypeError(MessageTemplate::kOrdinaryFunctionCalledAsConstructor, |
| isolate->factory()->NewStringFromStaticChars( |
| "Intl.v8BreakIterator"))); |
| } |
| |
| RETURN_RESULT_OR_FAILURE( |
| isolate, SupportedLocalesOfCommon(isolate, "breakiterator", args)); |
| } |
| |
| BUILTIN(NumberFormatSupportedLocalesOf) { |
| HandleScope scope(isolate); |
| RETURN_RESULT_OR_FAILURE( |
| isolate, SupportedLocalesOfCommon(isolate, "numberformat", args)); |
| } |
| |
| BUILTIN(NumberFormatPrototypeFormatToParts) { |
| const char* const method = "Intl.NumberFormat.prototype.formatToParts"; |
| HandleScope handle_scope(isolate); |
| CHECK_RECEIVER(JSNumberFormat, number_format, method); |
| |
| Handle<Object> x; |
| if (args.length() >= 2) { |
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, x, |
| Object::ToNumber(isolate, args.at(1))); |
| } else { |
| x = isolate->factory()->nan_value(); |
| } |
| |
| RETURN_RESULT_OR_FAILURE(isolate, JSNumberFormat::FormatToParts( |
| isolate, number_format, x->Number())); |
| } |
| |
| BUILTIN(DateTimeFormatPrototypeResolvedOptions) { |
| const char* const method = "Intl.DateTimeFormat.prototype.resolvedOptions"; |
| HandleScope scope(isolate); |
| CHECK_RECEIVER(JSReceiver, format_holder, method); |
| |
| // 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); |
| RETURN_RESULT_OR_FAILURE( |
| isolate, SupportedLocalesOfCommon(isolate, "dateformat", args)); |
| } |
| |
| BUILTIN(DateTimeFormatPrototypeFormatToParts) { |
| const char* const method = "Intl.DateTimeFormat.prototype.formatToParts"; |
| HandleScope handle_scope(isolate); |
| CHECK_RECEIVER(JSObject, date_format_holder, method); |
| Factory* factory = isolate->factory(); |
| |
| if (!date_format_holder->IsJSDateTimeFormat()) { |
| THROW_NEW_ERROR_RETURN_FAILURE( |
| isolate, NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, |
| factory->NewStringFromAsciiChecked(method), |
| date_format_holder)); |
| } |
| Handle<JSDateTimeFormat> dtf = |
| Handle<JSDateTimeFormat>::cast(date_format_holder); |
| |
| Handle<Object> x = args.atOrUndefined(isolate, 1); |
| if (x->IsUndefined(isolate)) { |
| x = factory->NewNumber(JSDate::CurrentTimeValue(isolate)); |
| } else { |
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, x, |
| Object::ToNumber(isolate, args.at(1))); |
| } |
| |
| double date_value = DateCache::TimeClip(x->Number()); |
| if (std::isnan(date_value)) { |
| THROW_NEW_ERROR_RETURN_FAILURE( |
| isolate, NewRangeError(MessageTemplate::kInvalidTimeValue)); |
| } |
| |
| RETURN_RESULT_OR_FAILURE( |
| isolate, JSDateTimeFormat::FormatToParts(isolate, dtf, date_value)); |
| } |
| |
| namespace { |
| Handle<JSFunction> CreateBoundFunction(Isolate* isolate, |
| Handle<JSObject> object, |
| Builtins::Name builtin_id, 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_id, kNormalFunction); |
| info->set_internal_formal_parameter_count(len); |
| info->set_length(len); |
| |
| Handle<Map> map = isolate->strict_function_without_prototype_map(); |
| |
| Handle<JSFunction> new_bound_function = |
| isolate->factory()->NewFunctionFromSharedFunctionInfo(map, info, context); |
| return new_bound_function; |
| } |
| |
| /** |
| * Common code shared between DateTimeFormatConstructor and |
| * NumberFormatConstrutor |
| */ |
| template <class T> |
| Object* FormatConstructor(BuiltinArguments args, Isolate* isolate, |
| Handle<Object> constructor, const char* method) { |
| Handle<JSReceiver> new_target; |
| // 1. If NewTarget is undefined, let newTarget be the active |
| // function object, else let newTarget be NewTarget. |
| if (args.new_target()->IsUndefined(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<JSObject> format_obj; |
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| isolate, format_obj, |
| JSObject::New(target, new_target, Handle<AllocationSite>::null())); |
| Handle<T> format = Handle<T>::cast(format_obj); |
| |
| // 3. Perform ? Initialize<T>(Format, locales, options). |
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| isolate, format, T::Initialize(isolate, format, locales, options)); |
| // 4. Let this be the this value. |
| Handle<Object> receiver = args.receiver(); |
| |
| // 5. If NewTarget is undefined and ? InstanceofOperator(this, %<T>%) |
| // is true, then |
| // |
| // Look up the intrinsic value that has been stored on the context. |
| // Call the instanceof function |
| Handle<Object> is_instance_of_obj; |
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| isolate, is_instance_of_obj, |
| Object::InstanceOf(isolate, receiver, constructor)); |
| |
| // Get the boolean value of the result |
| bool is_instance_of = is_instance_of_obj->BooleanValue(isolate); |
| |
| if (args.new_target()->IsUndefined(isolate) && is_instance_of) { |
| if (!receiver->IsJSReceiver()) { |
| THROW_NEW_ERROR_RETURN_FAILURE( |
| isolate, |
| NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, |
| isolate->factory()->NewStringFromAsciiChecked(method), |
| 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, |
| kThrowOnError); |
| MAYBE_RETURN(success, ReadOnlyRoots(isolate).exception()); |
| CHECK(success.FromJust()); |
| // b. b. Return this. |
| return *receiver; |
| } |
| // 6. Return format. |
| return *format; |
| } |
| |
| } // namespace |
| |
| BUILTIN(NumberFormatConstructor) { |
| HandleScope scope(isolate); |
| |
| isolate->CountUsage(v8::Isolate::UseCounterFeature::kNumberFormat); |
| |
| return FormatConstructor<JSNumberFormat>( |
| args, isolate, isolate->intl_number_format_function(), |
| "Intl.NumberFormat"); |
| } |
| |
| BUILTIN(NumberFormatPrototypeResolvedOptions) { |
| HandleScope scope(isolate); |
| const char* const method = "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); |
| |
| // 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 = "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); |
| |
| // 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 (!bound_format->IsUndefined(isolate)) { |
| DCHECK(bound_format->IsJSFunction()); |
| // 5. Return nf.[[BoundFormat]]. |
| return *bound_format; |
| } |
| |
| Handle<JSFunction> new_bound_format_function = CreateBoundFunction( |
| isolate, number_format, Builtins::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); |
| |
| // 4. Let x be ? ToNumber(value). |
| Handle<Object> number_obj; |
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, number_obj, |
| Object::ToNumber(isolate, value)); |
| |
| // Spec treats -0 as 0. |
| if (number_obj->IsMinusZero()) { |
| number_obj = Handle<Smi>(Smi::kZero, isolate); |
| } |
| |
| double number = number_obj->Number(); |
| // Return FormatNumber(nf, x). |
| RETURN_RESULT_OR_FAILURE( |
| isolate, JSNumberFormat::FormatNumber(isolate, number_format, number)); |
| } |
| |
| BUILTIN(DateTimeFormatConstructor) { |
| HandleScope scope(isolate); |
| |
| isolate->CountUsage(v8::Isolate::UseCounterFeature::kDateTimeFormat); |
| |
| return FormatConstructor<JSDateTimeFormat>( |
| args, isolate, isolate->intl_date_time_format_function(), |
| "Intl.DateTimeFormat"); |
| } |
| |
| BUILTIN(DateTimeFormatPrototypeFormat) { |
| const char* const method = "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); |
| |
| // 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 (!bound_format->IsUndefined(isolate)) { |
| DCHECK(bound_format->IsJSFunction()); |
| // 5. Return dtf.[[BoundFormat]]. |
| return *bound_format; |
| } |
| |
| Handle<JSFunction> new_bound_format_function = CreateBoundFunction( |
| isolate, format, Builtins::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)); |
| } |
| |
| BUILTIN(ListFormatConstructor) { |
| HandleScope scope(isolate); |
| |
| isolate->CountUsage(v8::Isolate::UseCounterFeature::kListFormat); |
| |
| // 1. If NewTarget is undefined, throw a TypeError exception. |
| if (args.new_target()->IsUndefined(isolate)) { // [[Call]] |
| THROW_NEW_ERROR_RETURN_FAILURE( |
| isolate, NewTypeError(MessageTemplate::kConstructorNotFunction, |
| isolate->factory()->NewStringFromStaticChars( |
| "Intl.ListFormat"))); |
| } |
| // [[Construct]] |
| Handle<JSFunction> target = args.target(); |
| Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target()); |
| |
| Handle<JSObject> result; |
| // 2. Let listFormat be OrdinaryCreateFromConstructor(NewTarget, |
| // "%ListFormatPrototype%"). |
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| isolate, result, |
| JSObject::New(target, new_target, Handle<AllocationSite>::null())); |
| Handle<JSListFormat> format = Handle<JSListFormat>::cast(result); |
| format->set_flags(0); |
| |
| Handle<Object> locales = args.atOrUndefined(isolate, 1); |
| Handle<Object> options = args.atOrUndefined(isolate, 2); |
| |
| // 3. Return InitializeListFormat(listFormat, locales, options). |
| RETURN_RESULT_OR_FAILURE( |
| isolate, JSListFormat::Initialize(isolate, format, locales, options)); |
| } |
| |
| 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); |
| RETURN_RESULT_OR_FAILURE( |
| isolate, SupportedLocalesOfCommon(isolate, "listformat", args)); |
| } |
| |
| namespace { |
| |
| MaybeHandle<JSLocale> CreateLocale(Isolate* isolate, |
| Handle<JSFunction> constructor, |
| Handle<JSReceiver> new_target, |
| Handle<Object> tag, Handle<Object> options) { |
| Handle<JSObject> result; |
| ASSIGN_RETURN_ON_EXCEPTION( |
| isolate, result, |
| JSObject::New(constructor, new_target, Handle<AllocationSite>::null()), |
| JSLocale); |
| |
| // First parameter is a locale, as a string/object. Can't be empty. |
| if (!tag->IsString() && !tag->IsJSReceiver()) { |
| THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kLocaleNotEmpty), |
| JSLocale); |
| } |
| |
| Handle<String> locale_string; |
| if (tag->IsJSLocale() && Handle<JSLocale>::cast(tag)->locale()->IsString()) { |
| locale_string = |
| Handle<String>(Handle<JSLocale>::cast(tag)->locale(), isolate); |
| } else { |
| ASSIGN_RETURN_ON_EXCEPTION(isolate, locale_string, |
| Object::ToString(isolate, tag), JSLocale); |
| } |
| |
| Handle<JSReceiver> options_object; |
| if (options->IsNullOrUndefined(isolate)) { |
| // Make empty options bag. |
| options_object = isolate->factory()->NewJSObjectWithNullProto(); |
| } else { |
| ASSIGN_RETURN_ON_EXCEPTION(isolate, options_object, |
| Object::ToObject(isolate, options), JSLocale); |
| } |
| |
| return JSLocale::Initialize(isolate, Handle<JSLocale>::cast(result), |
| locale_string, options_object); |
| } |
| |
| } // namespace |
| |
| // Intl.Locale implementation |
| BUILTIN(LocaleConstructor) { |
| HandleScope scope(isolate); |
| |
| isolate->CountUsage(v8::Isolate::UseCounterFeature::kLocale); |
| |
| if (args.new_target()->IsUndefined(isolate)) { // [[Call]] |
| THROW_NEW_ERROR_RETURN_FAILURE( |
| isolate, NewTypeError(MessageTemplate::kConstructorNotFunction, |
| isolate->factory()->NewStringFromAsciiChecked( |
| "Intl.Locale"))); |
| } |
| // [[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); |
| |
| RETURN_RESULT_OR_FAILURE( |
| isolate, CreateLocale(isolate, target, new_target, tag, options)); |
| } |
| |
| BUILTIN(LocalePrototypeMaximize) { |
| HandleScope scope(isolate); |
| CHECK_RECEIVER(JSLocale, locale_holder, "Intl.Locale.prototype.maximize"); |
| Handle<JSFunction> constructor( |
| isolate->native_context()->intl_locale_function(), isolate); |
| RETURN_RESULT_OR_FAILURE( |
| isolate, |
| CreateLocale(isolate, constructor, constructor, |
| JSLocale::Maximize(isolate, locale_holder->locale()), |
| isolate->factory()->NewJSObjectWithNullProto())); |
| } |
| |
| BUILTIN(LocalePrototypeMinimize) { |
| HandleScope scope(isolate); |
| CHECK_RECEIVER(JSLocale, locale_holder, "Intl.Locale.prototype.minimize"); |
| Handle<JSFunction> constructor( |
| isolate->native_context()->intl_locale_function(), isolate); |
| RETURN_RESULT_OR_FAILURE( |
| isolate, |
| CreateLocale(isolate, constructor, constructor, |
| JSLocale::Minimize(isolate, locale_holder->locale()), |
| isolate->factory()->NewJSObjectWithNullProto())); |
| } |
| |
| BUILTIN(RelativeTimeFormatSupportedLocalesOf) { |
| HandleScope scope(isolate); |
| RETURN_RESULT_OR_FAILURE( |
| isolate, SupportedLocalesOfCommon(isolate, "relativetimeformat", args)); |
| } |
| |
| 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, "format", false)); |
| } |
| |
| 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::Format( |
| isolate, value_obj, unit_obj, |
| format_holder, "formatToParts", true)); |
| } |
| |
| // Locale getters. |
| BUILTIN(LocalePrototypeLanguage) { |
| HandleScope scope(isolate); |
| // CHECK_RECEIVER will case locale_holder to JSLocale. |
| CHECK_RECEIVER(JSLocale, locale_holder, "Intl.Locale.prototype.language"); |
| |
| return locale_holder->language(); |
| } |
| |
| BUILTIN(LocalePrototypeScript) { |
| HandleScope scope(isolate); |
| CHECK_RECEIVER(JSLocale, locale_holder, "Intl.Locale.prototype.script"); |
| |
| return locale_holder->script(); |
| } |
| |
| BUILTIN(LocalePrototypeRegion) { |
| HandleScope scope(isolate); |
| CHECK_RECEIVER(JSLocale, locale_holder, "Intl.Locale.prototype.region"); |
| |
| return locale_holder->region(); |
| } |
| |
| BUILTIN(LocalePrototypeBaseName) { |
| HandleScope scope(isolate); |
| CHECK_RECEIVER(JSLocale, locale_holder, "Intl.Locale.prototype.baseName"); |
| |
| return locale_holder->base_name(); |
| } |
| |
| BUILTIN(LocalePrototypeCalendar) { |
| HandleScope scope(isolate); |
| CHECK_RECEIVER(JSLocale, locale_holder, "Intl.Locale.prototype.calendar"); |
| |
| return locale_holder->calendar(); |
| } |
| |
| BUILTIN(LocalePrototypeCaseFirst) { |
| HandleScope scope(isolate); |
| CHECK_RECEIVER(JSLocale, locale_holder, "Intl.Locale.prototype.caseFirst"); |
| |
| return locale_holder->case_first(); |
| } |
| |
| BUILTIN(LocalePrototypeCollation) { |
| HandleScope scope(isolate); |
| CHECK_RECEIVER(JSLocale, locale_holder, "Intl.Locale.prototype.collation"); |
| |
| return locale_holder->collation(); |
| } |
| |
| BUILTIN(LocalePrototypeHourCycle) { |
| HandleScope scope(isolate); |
| CHECK_RECEIVER(JSLocale, locale_holder, "Intl.Locale.prototype.hourCycle"); |
| |
| return locale_holder->hour_cycle(); |
| } |
| |
| BUILTIN(LocalePrototypeNumeric) { |
| HandleScope scope(isolate); |
| CHECK_RECEIVER(JSLocale, locale_holder, "Intl.Locale.prototype.numeric"); |
| |
| return locale_holder->numeric(); |
| } |
| |
| BUILTIN(LocalePrototypeNumberingSystem) { |
| HandleScope scope(isolate); |
| CHECK_RECEIVER(JSLocale, locale_holder, |
| "Intl.Locale.prototype.numberingSystem"); |
| |
| return locale_holder->numbering_system(); |
| } |
| |
| BUILTIN(LocalePrototypeToString) { |
| HandleScope scope(isolate); |
| CHECK_RECEIVER(JSLocale, locale_holder, "Intl.Locale.prototype.toString"); |
| |
| return locale_holder->locale(); |
| } |
| |
| BUILTIN(RelativeTimeFormatConstructor) { |
| HandleScope scope(isolate); |
| |
| isolate->CountUsage(v8::Isolate::UseCounterFeature::kRelativeTimeFormat); |
| |
| // 1. If NewTarget is undefined, throw a TypeError exception. |
| if (args.new_target()->IsUndefined(isolate)) { // [[Call]] |
| THROW_NEW_ERROR_RETURN_FAILURE( |
| isolate, NewTypeError(MessageTemplate::kConstructorNotFunction, |
| isolate->factory()->NewStringFromStaticChars( |
| "Intl.RelativeTimeFormat"))); |
| } |
| // [[Construct]] |
| Handle<JSFunction> target = args.target(); |
| Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target()); |
| |
| Handle<JSObject> result; |
| // 2. Let relativeTimeFormat be |
| // ! OrdinaryCreateFromConstructor(NewTarget, |
| // "%RelativeTimeFormatPrototype%"). |
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| isolate, result, |
| JSObject::New(target, new_target, Handle<AllocationSite>::null())); |
| Handle<JSRelativeTimeFormat> format = |
| Handle<JSRelativeTimeFormat>::cast(result); |
| format->set_flags(0); |
| |
| Handle<Object> locales = args.atOrUndefined(isolate, 1); |
| Handle<Object> options = args.atOrUndefined(isolate, 2); |
| |
| // 3. Return ? InitializeRelativeTimeFormat(relativeTimeFormat, locales, |
| // options). |
| RETURN_RESULT_OR_FAILURE(isolate, JSRelativeTimeFormat::Initialize( |
| isolate, format, locales, options)); |
| } |
| |
| BUILTIN(RelativeTimeFormatPrototypeResolvedOptions) { |
| HandleScope scope(isolate); |
| CHECK_RECEIVER(JSRelativeTimeFormat, format_holder, |
| "Intl.RelativeTimeFormat.prototype.resolvedOptions"); |
| return *JSRelativeTimeFormat::ResolvedOptions(isolate, format_holder); |
| } |
| |
| BUILTIN(StringPrototypeToLocaleLowerCase) { |
| HandleScope scope(isolate); |
| |
| isolate->CountUsage(v8::Isolate::UseCounterFeature::kStringToLocaleLowerCase); |
| |
| TO_THIS_STRING(string, "String.prototype.toLocaleLowerCase"); |
| |
| RETURN_RESULT_OR_FAILURE( |
| isolate, Intl::StringLocaleConvertCase(isolate, string, false, |
| args.atOrUndefined(isolate, 1))); |
| } |
| |
| BUILTIN(StringPrototypeToLocaleUpperCase) { |
| HandleScope scope(isolate); |
| |
| isolate->CountUsage(v8::Isolate::UseCounterFeature::kStringToLocaleUpperCase); |
| |
| TO_THIS_STRING(string, "String.prototype.toLocaleUpperCase"); |
| |
| RETURN_RESULT_OR_FAILURE( |
| isolate, Intl::StringLocaleConvertCase(isolate, string, true, |
| args.atOrUndefined(isolate, 1))); |
| } |
| |
| BUILTIN(PluralRulesConstructor) { |
| HandleScope scope(isolate); |
| |
| isolate->CountUsage(v8::Isolate::UseCounterFeature::kPluralRules); |
| |
| // 1. If NewTarget is undefined, throw a TypeError exception. |
| if (args.new_target()->IsUndefined(isolate)) { // [[Call]] |
| THROW_NEW_ERROR_RETURN_FAILURE( |
| isolate, NewTypeError(MessageTemplate::kConstructorNotFunction, |
| isolate->factory()->NewStringFromStaticChars( |
| "Intl.PluralRules"))); |
| } |
| |
| // [[Construct]] |
| Handle<JSFunction> target = args.target(); |
| Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target()); |
| |
| Handle<Object> locales = args.atOrUndefined(isolate, 1); |
| Handle<Object> options = args.atOrUndefined(isolate, 2); |
| |
| // 2. Let pluralRules be ? OrdinaryCreateFromConstructor(newTarget, |
| // "%PluralRulesPrototype%", « [[InitializedPluralRules]], |
| // [[Locale]], [[Type]], [[MinimumIntegerDigits]], |
| // [[MinimumFractionDigits]], [[MaximumFractionDigits]], |
| // [[MinimumSignificantDigits]], [[MaximumSignificantDigits]] »). |
| Handle<JSObject> plural_rules_obj; |
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| isolate, plural_rules_obj, |
| JSObject::New(target, new_target, Handle<AllocationSite>::null())); |
| Handle<JSPluralRules> plural_rules = |
| Handle<JSPluralRules>::cast(plural_rules_obj); |
| |
| // 3. Return ? InitializePluralRules(pluralRules, locales, options). |
| RETURN_RESULT_OR_FAILURE( |
| isolate, |
| JSPluralRules::Initialize(isolate, plural_rules, locales, options)); |
| } |
| |
| 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. Let pr be the this value. |
| // 2. If Type(pr) is not Object, throw a TypeError exception. |
| // 3. If pr does not have an [[InitializedPluralRules]] internal slot, throw a |
| // TypeError exception. |
| CHECK_RECEIVER(JSPluralRules, plural_rules, |
| "Intl.PluralRules.prototype.select"); |
| |
| // 4. 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 = number->Number(); |
| |
| // 5. Return ? ResolvePlural(pr, n). |
| RETURN_RESULT_OR_FAILURE(isolate, JSPluralRules::ResolvePlural( |
| isolate, plural_rules, number_double)); |
| } |
| |
| BUILTIN(PluralRulesSupportedLocalesOf) { |
| HandleScope scope(isolate); |
| RETURN_RESULT_OR_FAILURE( |
| isolate, SupportedLocalesOfCommon(isolate, "pluralrules", args)); |
| } |
| |
| BUILTIN(CollatorConstructor) { |
| HandleScope scope(isolate); |
| |
| isolate->CountUsage(v8::Isolate::UseCounterFeature::kCollator); |
| |
| Handle<JSReceiver> new_target; |
| // 1. If NewTarget is undefined, let newTarget be the active |
| // function object, else let newTarget be NewTarget. |
| if (args.new_target()->IsUndefined(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); |
| |
| // 5. Let collator be ? OrdinaryCreateFromConstructor(newTarget, |
| // "%CollatorPrototype%", internalSlotsList). |
| Handle<JSObject> collator_obj; |
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| isolate, collator_obj, |
| JSObject::New(target, new_target, Handle<AllocationSite>::null())); |
| Handle<JSCollator> collator = Handle<JSCollator>::cast(collator_obj); |
| |
| // 6. Return ? InitializeCollator(collator, locales, options). |
| RETURN_RESULT_OR_FAILURE( |
| isolate, JSCollator::Initialize(isolate, collator, locales, options)); |
| } |
| |
| 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); |
| RETURN_RESULT_OR_FAILURE(isolate, |
| SupportedLocalesOfCommon(isolate, "collator", args)); |
| } |
| |
| BUILTIN(CollatorPrototypeCompare) { |
| const char* const method = "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); |
| |
| // 4. If collator.[[BoundCompare]] is undefined, then |
| Handle<Object> bound_compare(collator->bound_compare(), isolate); |
| if (!bound_compare->IsUndefined(isolate)) { |
| DCHECK(bound_compare->IsJSFunction()); |
| // 5. Return collator.[[BoundCompare]]. |
| return *bound_compare; |
| } |
| |
| Handle<JSFunction> new_bound_compare_function = CreateBoundFunction( |
| isolate, collator, Builtins::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_holder = 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). |
| return *Intl::CompareStrings(isolate, collator_holder, string_x, string_y); |
| } |
| |
| BUILTIN(V8BreakIteratorConstructor) { |
| HandleScope scope(isolate); |
| Handle<JSReceiver> new_target; |
| |
| if (args.new_target()->IsUndefined(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<JSObject> break_iterator_obj; |
| ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| isolate, break_iterator_obj, |
| JSObject::New(target, new_target, Handle<AllocationSite>::null())); |
| Handle<JSV8BreakIterator> break_iterator = |
| Handle<JSV8BreakIterator>::cast(break_iterator_obj); |
| |
| RETURN_RESULT_OR_FAILURE( |
| isolate, |
| JSV8BreakIterator::Initialize(isolate, break_iterator, locales, options)); |
| } |
| |
| 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 = "get Intl.v8BreakIterator.prototype.adoptText"; |
| HandleScope scope(isolate); |
| |
| CHECK_RECEIVER(JSV8BreakIterator, break_iterator, method); |
| |
| Handle<Object> bound_adopt_text(break_iterator->bound_adopt_text(), isolate); |
| if (!bound_adopt_text->IsUndefined(isolate)) { |
| DCHECK(bound_adopt_text->IsJSFunction()); |
| return *bound_adopt_text; |
| } |
| |
| Handle<JSFunction> new_bound_adopt_text_function = CreateBoundFunction( |
| isolate, break_iterator, Builtins::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_holder = 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_holder, text); |
| return ReadOnlyRoots(isolate).undefined_value(); |
| } |
| |
| BUILTIN(V8BreakIteratorPrototypeFirst) { |
| const char* const method = "get Intl.v8BreakIterator.prototype.first"; |
| HandleScope scope(isolate); |
| |
| CHECK_RECEIVER(JSV8BreakIterator, break_iterator_holder, method); |
| |
| Handle<Object> bound_first(break_iterator_holder->bound_first(), isolate); |
| if (!bound_first->IsUndefined(isolate)) { |
| DCHECK(bound_first->IsJSFunction()); |
| return *bound_first; |
| } |
| |
| Handle<JSFunction> new_bound_first_function = |
| CreateBoundFunction(isolate, break_iterator_holder, |
| Builtins::kV8BreakIteratorInternalFirst, 0); |
| break_iterator_holder->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_holder = Handle<JSV8BreakIterator>( |
| JSV8BreakIterator::cast(context->get( |
| static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction))), |
| isolate); |
| |
| icu::BreakIterator* break_iterator = |
| break_iterator_holder->break_iterator()->raw(); |
| CHECK_NOT_NULL(break_iterator); |
| |
| return *isolate->factory()->NewNumberFromInt(break_iterator->first()); |
| } |
| |
| BUILTIN(V8BreakIteratorPrototypeNext) { |
| const char* const method = "get Intl.v8BreakIterator.prototype.next"; |
| HandleScope scope(isolate); |
| |
| CHECK_RECEIVER(JSV8BreakIterator, break_iterator_holder, method); |
| |
| Handle<Object> bound_next(break_iterator_holder->bound_next(), isolate); |
| if (!bound_next->IsUndefined(isolate)) { |
| DCHECK(bound_next->IsJSFunction()); |
| return *bound_next; |
| } |
| |
| Handle<JSFunction> new_bound_next_function = |
| CreateBoundFunction(isolate, break_iterator_holder, |
| Builtins::kV8BreakIteratorInternalNext, 0); |
| break_iterator_holder->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_holder = Handle<JSV8BreakIterator>( |
| JSV8BreakIterator::cast(context->get( |
| static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction))), |
| isolate); |
| |
| icu::BreakIterator* break_iterator = |
| break_iterator_holder->break_iterator()->raw(); |
| CHECK_NOT_NULL(break_iterator); |
| |
| return *isolate->factory()->NewNumberFromInt(break_iterator->next()); |
| } |
| |
| BUILTIN(V8BreakIteratorPrototypeCurrent) { |
| const char* const method = "get Intl.v8BreakIterator.prototype.current"; |
| HandleScope scope(isolate); |
| |
| CHECK_RECEIVER(JSV8BreakIterator, break_iterator_holder, method); |
| |
| Handle<Object> bound_current(break_iterator_holder->bound_current(), isolate); |
| if (!bound_current->IsUndefined(isolate)) { |
| DCHECK(bound_current->IsJSFunction()); |
| return *bound_current; |
| } |
| |
| Handle<JSFunction> new_bound_current_function = |
| CreateBoundFunction(isolate, break_iterator_holder, |
| Builtins::kV8BreakIteratorInternalCurrent, 0); |
| break_iterator_holder->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_holder = Handle<JSV8BreakIterator>( |
| JSV8BreakIterator::cast(context->get( |
| static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction))), |
| isolate); |
| |
| icu::BreakIterator* break_iterator = |
| break_iterator_holder->break_iterator()->raw(); |
| CHECK_NOT_NULL(break_iterator); |
| |
| return *isolate->factory()->NewNumberFromInt(break_iterator->current()); |
| } |
| |
| BUILTIN(V8BreakIteratorPrototypeBreakType) { |
| const char* const method = "get Intl.v8BreakIterator.prototype.breakType"; |
| HandleScope scope(isolate); |
| |
| CHECK_RECEIVER(JSV8BreakIterator, break_iterator_holder, method); |
| |
| Handle<Object> bound_break_type(break_iterator_holder->bound_break_type(), |
| isolate); |
| if (!bound_break_type->IsUndefined(isolate)) { |
| DCHECK(bound_break_type->IsJSFunction()); |
| return *bound_break_type; |
| } |
| |
| Handle<JSFunction> new_bound_break_type_function = |
| CreateBoundFunction(isolate, break_iterator_holder, |
| Builtins::kV8BreakIteratorInternalBreakType, 0); |
| break_iterator_holder->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_holder = Handle<JSV8BreakIterator>( |
| JSV8BreakIterator::cast(context->get( |
| static_cast<int>(Intl::BoundFunctionContextSlot::kBoundFunction))), |
| isolate); |
| |
| icu::BreakIterator* break_iterator = |
| break_iterator_holder->break_iterator()->raw(); |
| CHECK_NOT_NULL(break_iterator); |
| |
| int32_t status = break_iterator->getRuleStatus(); |
| // Keep return values in sync with JavaScript BreakType enum. |
| if (status >= UBRK_WORD_NONE && status < UBRK_WORD_NONE_LIMIT) { |
| return *isolate->factory()->NewStringFromStaticChars("none"); |
| } else if (status >= UBRK_WORD_NUMBER && status < UBRK_WORD_NUMBER_LIMIT) { |
| return ReadOnlyRoots(isolate).number_string(); |
| } else if (status >= UBRK_WORD_LETTER && status < UBRK_WORD_LETTER_LIMIT) { |
| return *isolate->factory()->NewStringFromStaticChars("letter"); |
| } else if (status >= UBRK_WORD_KANA && status < UBRK_WORD_KANA_LIMIT) { |
| return *isolate->factory()->NewStringFromStaticChars("kana"); |
| } else if (status >= UBRK_WORD_IDEO && status < UBRK_WORD_IDEO_LIMIT) { |
| return *isolate->factory()->NewStringFromStaticChars("ideo"); |
| } else { |
| return *isolate->factory()->NewStringFromStaticChars("unknown"); |
| } |
| } |
| |
| } // namespace internal |
| } // namespace v8 |