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