• 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-inl.h"
20 #include "src/objects/objects-inl.h"
21 #include "src/objects/option-utils.h"
22 #include "unicode/brkiter.h"
23 
24 namespace v8 {
25 namespace internal {
26 
New(Isolate * isolate,Handle<Map> map,Handle<Object> locales,Handle<Object> input_options)27 MaybeHandle<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
ResolvedOptions(Isolate * isolate,Handle<JSSegmenter> segmenter)127 Handle<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 
GranularityAsString(Isolate * isolate) const153 Handle<String> JSSegmenter::GranularityAsString(Isolate* isolate) const {
154   return GetGranularityString(isolate, granularity());
155 }
156 
GetGranularityString(Isolate * isolate,Granularity granularity)157 Handle<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 
GetAvailableLocales()171 const std::set<std::string>& JSSegmenter::GetAvailableLocales() {
172   return Intl::GetAvailableLocales();
173 }
174 
175 }  // namespace internal
176 }  // namespace v8
177