1// Copyright 2018 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#ifndef V8_INTL_SUPPORT 6#error Internationalization is expected to be enabled. 7#endif // V8_INTL_SUPPORT 8 9#include "src/objects/js-segmenter.h" 10 11#include <map> 12#include <memory> 13#include <string> 14 15#include "src/execution/isolate.h" 16#include "src/heap/factory.h" 17#include "src/objects/intl-objects.h" 18#include "src/objects/js-segmenter-inl.h" 19#include "src/objects/managed-inl.h" 20#include "src/objects/objects-inl.h" 21#include "src/objects/option-utils.h" 22#include "unicode/brkiter.h" 23 24namespace v8 { 25namespace internal { 26 27MaybeHandle<JSSegmenter> JSSegmenter::New(Isolate* isolate, Handle<Map> map, 28 Handle<Object> locales, 29 Handle<Object> input_options) { 30 // 4. Let requestedLocales be ? CanonicalizeLocaleList(locales). 31 Maybe<std::vector<std::string>> maybe_requested_locales = 32 Intl::CanonicalizeLocaleList(isolate, locales); 33 MAYBE_RETURN(maybe_requested_locales, Handle<JSSegmenter>()); 34 std::vector<std::string> requested_locales = 35 maybe_requested_locales.FromJust(); 36 37 Handle<JSReceiver> options; 38 const char* service = "Intl.Segmenter"; 39 // 5. Let options be GetOptionsObject(_options_). 40 ASSIGN_RETURN_ON_EXCEPTION(isolate, options, 41 GetOptionsObject(isolate, input_options, service), 42 JSSegmenter); 43 44 // 7. Let opt be a new Record. 45 // 8. Let matcher be ? GetOption(options, "localeMatcher", "string", 46 // « "lookup", "best fit" », "best fit"). 47 // 9. Set opt.[[localeMatcher]] to matcher. 48 Maybe<Intl::MatcherOption> maybe_locale_matcher = 49 Intl::GetLocaleMatcher(isolate, options, service); 50 MAYBE_RETURN(maybe_locale_matcher, MaybeHandle<JSSegmenter>()); 51 Intl::MatcherOption matcher = maybe_locale_matcher.FromJust(); 52 53 // 10. Let localeData be %Segmenter%.[[LocaleData]]. 54 55 // 11. Let r be ResolveLocale(%Segmenter%.[[AvailableLocales]], 56 // requestedLocales, opt, %Segmenter%.[[RelevantExtensionKeys]]). 57 Maybe<Intl::ResolvedLocale> maybe_resolve_locale = 58 Intl::ResolveLocale(isolate, JSSegmenter::GetAvailableLocales(), 59 requested_locales, matcher, {}); 60 if (maybe_resolve_locale.IsNothing()) { 61 THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kIcuError), 62 JSSegmenter); 63 } 64 Intl::ResolvedLocale r = maybe_resolve_locale.FromJust(); 65 66 // 12. Set segmenter.[[Locale]] to the value of r.[[locale]]. 67 Handle<String> locale_str = 68 isolate->factory()->NewStringFromAsciiChecked(r.locale.c_str()); 69 70 // 13. Let granularity be ? GetOption(options, "granularity", "string", « 71 // "grapheme", "word", "sentence" », "grapheme"). 72 Maybe<Granularity> maybe_granularity = GetStringOption<Granularity>( 73 isolate, options, "granularity", service, 74 {"grapheme", "word", "sentence"}, 75 {Granularity::GRAPHEME, Granularity::WORD, Granularity::SENTENCE}, 76 Granularity::GRAPHEME); 77 MAYBE_RETURN(maybe_granularity, MaybeHandle<JSSegmenter>()); 78 Granularity granularity_enum = maybe_granularity.FromJust(); 79 80 icu::Locale icu_locale = r.icu_locale; 81 DCHECK(!icu_locale.isBogus()); 82 83 UErrorCode status = U_ZERO_ERROR; 84 std::unique_ptr<icu::BreakIterator> icu_break_iterator; 85 86 switch (granularity_enum) { 87 case Granularity::GRAPHEME: 88 icu_break_iterator.reset( 89 icu::BreakIterator::createCharacterInstance(icu_locale, status)); 90 break; 91 case Granularity::WORD: 92 icu_break_iterator.reset( 93 icu::BreakIterator::createWordInstance(icu_locale, status)); 94 break; 95 case Granularity::SENTENCE: 96 icu_break_iterator.reset( 97 icu::BreakIterator::createSentenceInstance(icu_locale, status)); 98 break; 99 } 100 101 DCHECK(U_SUCCESS(status)); 102 DCHECK_NOT_NULL(icu_break_iterator.get()); 103 104 Handle<Managed<icu::BreakIterator>> managed_break_iterator = 105 Managed<icu::BreakIterator>::FromUniquePtr(isolate, 0, 106 std::move(icu_break_iterator)); 107 108 // Now all properties are ready, so we can allocate the result object. 109 Handle<JSSegmenter> segmenter = Handle<JSSegmenter>::cast( 110 isolate->factory()->NewFastOrSlowJSObjectFromMap(map)); 111 DisallowGarbageCollection no_gc; 112 segmenter->set_flags(0); 113 114 // 12. Set segmenter.[[Locale]] to the value of r.[[Locale]]. 115 segmenter->set_locale(*locale_str); 116 117 // 14. Set segmenter.[[SegmenterGranularity]] to granularity. 118 segmenter->set_granularity(granularity_enum); 119 120 segmenter->set_icu_break_iterator(*managed_break_iterator); 121 122 // 15. Return segmenter. 123 return segmenter; 124} 125 126// ecma402 #sec-Intl.Segmenter.prototype.resolvedOptions 127Handle<JSObject> JSSegmenter::ResolvedOptions(Isolate* isolate, 128 Handle<JSSegmenter> segmenter) { 129 Factory* factory = isolate->factory(); 130 // 3. Let options be ! ObjectCreate(%ObjectPrototype%). 131 Handle<JSObject> result = factory->NewJSObject(isolate->object_function()); 132 // 4. For each row of Table 1, except the header row, do 133 // a. Let p be the Property value of the current row. 134 // b. Let v be the value of pr's internal slot whose name is the Internal Slot 135 // value of the current row. 136 // 137 // c. If v is not undefined, then 138 // i. Perform ! CreateDataPropertyOrThrow(options, p, v). 139 // Table 1: Resolved Options of Segmenter Instances 140 // Internal Slot Property 141 // [[Locale]] "locale" 142 // [[SegmenterGranularity]] "granularity" 143 144 Handle<String> locale(segmenter->locale(), isolate); 145 JSObject::AddProperty(isolate, result, factory->locale_string(), locale, 146 NONE); 147 JSObject::AddProperty(isolate, result, factory->granularity_string(), 148 segmenter->GranularityAsString(isolate), NONE); 149 // 5. Return options. 150 return result; 151} 152 153Handle<String> JSSegmenter::GranularityAsString(Isolate* isolate) const { 154 return GetGranularityString(isolate, granularity()); 155} 156 157Handle<String> JSSegmenter::GetGranularityString(Isolate* isolate, 158 Granularity granularity) { 159 Factory* factory = isolate->factory(); 160 switch (granularity) { 161 case Granularity::GRAPHEME: 162 return factory->grapheme_string(); 163 case Granularity::WORD: 164 return factory->word_string(); 165 case Granularity::SENTENCE: 166 return factory->sentence_string(); 167 } 168 UNREACHABLE(); 169} 170 171const std::set<std::string>& JSSegmenter::GetAvailableLocales() { 172 return Intl::GetAvailableLocales(); 173} 174 175} // namespace internal 176} // namespace v8 177