lin
2025-07-30 fcd736bf35fd93b563e9bbf594f2aa7b62028cc9
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
// Copyright 2013 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
 
#ifndef V8_OBJECTS_INTL_OBJECTS_H_
#define V8_OBJECTS_INTL_OBJECTS_H_
 
#include <map>
#include <set>
#include <string>
 
#include "src/contexts.h"
#include "src/intl.h"
#include "src/objects.h"
#include "unicode/locid.h"
#include "unicode/uversion.h"
 
namespace U_ICU_NAMESPACE {
class BreakIterator;
class Collator;
class DecimalFormat;
class PluralRules;
class SimpleDateFormat;
class UnicodeString;
}
 
namespace v8 {
namespace internal {
 
template <typename T>
class Handle;
 
class DateFormat {
 public:
  // Create a formatter for the specificied locale and options. Returns the
  // resolved settings for the locale / options.
  static icu::SimpleDateFormat* InitializeDateTimeFormat(
      Isolate* isolate, Handle<String> locale, Handle<JSObject> options,
      Handle<JSObject> resolved);
 
  // Unpacks date format object from corresponding JavaScript object.
  static icu::SimpleDateFormat* UnpackDateFormat(Handle<JSObject> obj);
 
  // Release memory we allocated for the DateFormat once the JS object that
  // holds the pointer gets garbage collected.
  static void DeleteDateFormat(const v8::WeakCallbackInfo<void>& data);
 
  // ecma402/#sec-formatdatetime
  // FormatDateTime( dateTimeFormat, x )
  V8_WARN_UNUSED_RESULT static MaybeHandle<String> FormatDateTime(
      Isolate* isolate, Handle<JSObject> date_time_format_holder, double x);
 
  // ecma402/#sec-datetime-format-functions
  // DateTime Format Functions
  V8_WARN_UNUSED_RESULT static MaybeHandle<String> DateTimeFormat(
      Isolate* isolate, Handle<JSObject> date_time_format_holder,
      Handle<Object> date);
 
  // The UnwrapDateTimeFormat abstract operation gets the underlying
  // DateTimeFormat operation for various methods which implement ECMA-402 v1
  // semantics for supporting initializing existing Intl objects.
  //
  // ecma402/#sec-unwrapdatetimeformat
  V8_WARN_UNUSED_RESULT static MaybeHandle<JSObject> Unwrap(
      Isolate* isolate, Handle<JSReceiver> receiver, const char* method_name);
 
  // ecma-402/#sec-todatetimeoptions
  V8_WARN_UNUSED_RESULT static MaybeHandle<JSObject> ToDateTimeOptions(
      Isolate* isolate, Handle<Object> input_options, const char* required,
      const char* defaults);
 
  V8_WARN_UNUSED_RESULT static MaybeHandle<String> ToLocaleDateTime(
      Isolate* isolate, Handle<Object> date, Handle<Object> locales,
      Handle<Object> options, const char* required, const char* defaults,
      const char* service);
 
  // Layout description.
#define DATE_FORMAT_FIELDS(V)        \
  V(kSimpleDateFormat, kPointerSize) \
  V(kBoundFormat, kPointerSize)      \
  V(kSize, 0)
 
  DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, DATE_FORMAT_FIELDS)
#undef DATE_FORMAT_FIELDS
 
  // ContextSlot defines the context structure for the bound
  // DateTimeFormat.prototype.format function
  enum ContextSlot {
    kDateFormat = Context::MIN_CONTEXT_SLOTS,
 
    kLength
  };
 
  // TODO(ryzokuken): Remove this and use regular accessors once DateFormat is a
  // subclass of JSObject
  //
  // This needs to be consistent with the above Layout Description
  static const int kSimpleDateFormatIndex = 0;
  static const int kBoundFormatIndex = 1;
 
 private:
  DateFormat();
};
 
class NumberFormat {
 public:
  // Create a formatter for the specificied locale and options. Returns the
  // resolved settings for the locale / options.
  static icu::DecimalFormat* InitializeNumberFormat(Isolate* isolate,
                                                    Handle<String> locale,
                                                    Handle<JSObject> options,
                                                    Handle<JSObject> resolved);
 
  // Unpacks number format object from corresponding JavaScript object.
  static icu::DecimalFormat* UnpackNumberFormat(Handle<JSObject> obj);
 
  // Release memory we allocated for the NumberFormat once the JS object that
  // holds the pointer gets garbage collected.
  static void DeleteNumberFormat(const v8::WeakCallbackInfo<void>& data);
 
  // The UnwrapNumberFormat abstract operation gets the underlying
  // NumberFormat operation for various methods which implement
  // ECMA-402 v1 semantics for supporting initializing existing Intl
  // objects.
  //
  // ecma402/#sec-unwrapnumberformat
  static MaybeHandle<JSObject> Unwrap(Isolate* isolate,
                                      Handle<JSReceiver> receiver,
                                      const char* method_name);
 
  // ecm402/#sec-formatnumber
  static MaybeHandle<String> FormatNumber(Isolate* isolate,
                                          Handle<JSObject> number_format_holder,
                                          double value);
 
  // Layout description.
#define NUMBER_FORMAT_FIELDS(V)   \
  /* Pointer fields. */           \
  V(kDecimalFormat, kPointerSize) \
  V(kBoundFormat, kPointerSize)   \
  V(kSize, 0)
 
  DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, NUMBER_FORMAT_FIELDS)
#undef NUMBER_FORMAT_FIELDS
 
  // ContextSlot defines the context structure for the bound
  // NumberFormat.prototype.format function.
  enum ContextSlot {
    // The number format instance that the function holding this
    // context is bound to.
    kNumberFormat = Context::MIN_CONTEXT_SLOTS,
 
    kLength
  };
 
  // TODO(gsathya): Remove this and use regular accessors once
  // NumberFormat is a sub class of JSObject.
  //
  // This needs to be consistent with the above LayoutDescription.
  static const int kDecimalFormatIndex = 0;
  static const int kBoundFormatIndex = 1;
 
 private:
  NumberFormat();
};
 
class V8BreakIterator {
 public:
  // Create a BreakIterator for the specificied locale and options. Returns the
  // resolved settings for the locale / options.
  static icu::BreakIterator* InitializeBreakIterator(Isolate* isolate,
                                                     Handle<String> locale,
                                                     Handle<JSObject> options,
                                                     Handle<JSObject> resolved);
 
  // Unpacks break iterator object from corresponding JavaScript object.
  static icu::BreakIterator* UnpackBreakIterator(Handle<JSObject> obj);
 
  // Release memory we allocated for the BreakIterator once the JS object that
  // holds the pointer gets garbage collected.
  static void DeleteBreakIterator(const v8::WeakCallbackInfo<void>& data);
 
  static void AdoptText(Isolate* isolate,
                        Handle<JSObject> break_iterator_holder,
                        Handle<String> text);
 
  // Layout description.
#define BREAK_ITERATOR_FIELDS(V)   \
  /* Pointer fields. */            \
  V(kBreakIterator, kPointerSize)  \
  V(kUnicodeString, kPointerSize)  \
  V(kBoundAdoptText, kPointerSize) \
  V(kSize, 0)
 
  DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, BREAK_ITERATOR_FIELDS)
#undef BREAK_ITERATOR_FIELDS
 
  // ContextSlot defines the context structure for the bound
  // v8BreakIterator.prototype.adoptText function
  enum class ContextSlot {
    kV8BreakIterator = Context::MIN_CONTEXT_SLOTS,
 
    kLength
  };
 
  // TODO(ryzokuken): Remove this and use regular accessors once v8BreakIterator
  // is a subclass of JSObject
  //
  // This needs to be consistent with the above Layour Description
  static const int kBreakIteratorIndex = 0;
  static const int kUnicodeStringIndex = 1;
  static const int kBoundAdoptTextIndex = 2;
 
 private:
  V8BreakIterator();
};
 
class Intl {
 public:
  enum Type {
    kNumberFormat = 0,
    kCollator,
    kDateTimeFormat,
    kPluralRules,
    kBreakIterator,
    kLocale,
 
    kTypeCount
  };
 
  inline static Intl::Type TypeFromInt(int type);
  inline static Intl::Type TypeFromSmi(Smi* type);
 
  // Checks if the given object has the expected_type based by looking
  // up a private symbol on the object.
  //
  // TODO(gsathya): This should just be an instance type check once we
  // move all the Intl objects to C++.
  static bool IsObjectOfType(Isolate* isolate, Handle<Object> object,
                             Intl::Type expected_type);
 
  static IcuService StringToIcuService(Handle<String> service);
 
  // Gets the ICU locales for a given service. If there is a locale with a
  // script tag then the locales also include a locale without the script; eg,
  // pa_Guru_IN (language=Panjabi, script=Gurmukhi, country-India) would include
  // pa_IN.
  static std::set<std::string> GetAvailableLocales(const IcuService& service);
 
  static V8_WARN_UNUSED_RESULT MaybeHandle<JSObject> AvailableLocalesOf(
      Isolate* isolate, Handle<String> service);
 
  static MaybeHandle<JSObject> SupportedLocalesOf(Isolate* isolate,
                                                  Handle<String> service,
                                                  Handle<Object> locales_in,
                                                  Handle<Object> options_in);
 
  static std::string DefaultLocale(Isolate* isolate);
 
  static void DefineWEProperty(Isolate* isolate, Handle<JSObject> target,
                               Handle<Name> key, Handle<Object> value);
 
  // If locale has a script tag then return true and the locale without the
  // script else return false and an empty string
  static bool RemoveLocaleScriptTag(const std::string& icu_locale,
                                    std::string* locale_less_script);
 
  // Returns the underlying Intl receiver for various methods which
  // implement ECMA-402 v1 semantics for supporting initializing
  // existing Intl objects.
  V8_WARN_UNUSED_RESULT static MaybeHandle<JSObject> UnwrapReceiver(
      Isolate* isolate, Handle<JSReceiver> receiver,
      Handle<JSFunction> constructor, Intl::Type type,
      Handle<String> method_name /* TODO(gsathya): Make this char const* */,
      bool check_legacy_constructor = false);
 
  // The ResolveLocale abstract operation compares a BCP 47 language
  // priority list requestedLocales against the locales in
  // availableLocales and determines the best available language to
  // meet the request. availableLocales, requestedLocales, and
  // relevantExtensionKeys must be provided as List values, options
  // and localeData as Records.
  //
  // #ecma402/sec-partitiondatetimepattern
  //
  // Returns a JSObject with two properties:
  //   (1) locale
  //   (2) extension
  //
  // To access either, use JSObject::GetDataProperty.
  V8_WARN_UNUSED_RESULT static MaybeHandle<JSObject> ResolveLocale(
      Isolate* isolate, const char* service, Handle<Object> requestedLocales,
      Handle<Object> options);
 
  // This currently calls out to the JavaScript implementation of
  // CanonicalizeLocaleList.
  // Note: This is deprecated glue code, required only as long as ResolveLocale
  // still calls a JS implementation. The C++ successor is the overloaded
  // version below that returns a Maybe<std::vector<std::string>>.
  //
  // ecma402/#sec-canonicalizelocalelist
  V8_WARN_UNUSED_RESULT static MaybeHandle<JSObject> CanonicalizeLocaleListJS(
      Isolate* isolate, Handle<Object> locales);
 
  // ECMA402 9.2.10. GetOption( options, property, type, values, fallback)
  // ecma402/#sec-getoption
  //
  // This is specialized for the case when type is string.
  //
  // Instead of passing undefined for the values argument as the spec
  // defines, pass in an empty vector.
  //
  // Returns true if options object has the property and stores the
  // result in value. Returns false if the value is not found. The
  // caller is required to use fallback value appropriately in this
  // case.
  //
  // service is a string denoting the type of Intl object; used when
  // printing the error message.
  V8_WARN_UNUSED_RESULT static Maybe<bool> GetStringOption(
      Isolate* isolate, Handle<JSReceiver> options, const char* property,
      std::vector<const char*> values, const char* service,
      std::unique_ptr<char[]>* result);
 
  // ECMA402 9.2.10. GetOption( options, property, type, values, fallback)
  // ecma402/#sec-getoption
  //
  // This is specialized for the case when type is boolean.
  //
  // Returns true if options object has the property and stores the
  // result in value. Returns false if the value is not found. The
  // caller is required to use fallback value appropriately in this
  // case.
  //
  // service is a string denoting the type of Intl object; used when
  // printing the error message.
  V8_WARN_UNUSED_RESULT static Maybe<bool> GetBoolOption(
      Isolate* isolate, Handle<JSReceiver> options, const char* property,
      const char* service, bool* result);
 
  // Canonicalize the locale.
  // https://tc39.github.io/ecma402/#sec-canonicalizelanguagetag,
  // including type check and structural validity check.
  static Maybe<std::string> CanonicalizeLanguageTag(Isolate* isolate,
                                                    Handle<Object> locale_in);
 
  // https://tc39.github.io/ecma402/#sec-canonicalizelocalelist
  // {only_return_one_result} is an optimization for callers that only
  // care about the first result.
  static Maybe<std::vector<std::string>> CanonicalizeLocaleList(
      Isolate* isolate, Handle<Object> locales,
      bool only_return_one_result = false);
 
  // ecma-402/#sec-currencydigits
  // The currency is expected to an all upper case string value.
  static Handle<Smi> CurrencyDigits(Isolate* isolate, Handle<String> currency);
 
  // TODO(ftang): Remove this and use ICU to the conversion in the future
  static void ParseExtension(Isolate* isolate, const std::string& extension,
                             std::map<std::string, std::string>& out);
 
  V8_WARN_UNUSED_RESULT static MaybeHandle<JSObject> CreateNumberFormat(
      Isolate* isolate, Handle<String> locale, Handle<JSObject> options,
      Handle<JSObject> resolved);
 
  // ecma402/#sec-iswellformedcurrencycode
  static bool IsWellFormedCurrencyCode(Isolate* isolate,
                                       Handle<String> currency);
 
  // For locale sensitive functions
  V8_WARN_UNUSED_RESULT static MaybeHandle<String> StringLocaleConvertCase(
      Isolate* isolate, Handle<String> s, bool is_upper,
      Handle<Object> locales);
 
  V8_WARN_UNUSED_RESULT static MaybeHandle<Object> StringLocaleCompare(
      Isolate* isolate, Handle<String> s1, Handle<String> s2,
      Handle<Object> locales, Handle<Object> options);
 
  V8_WARN_UNUSED_RESULT static Handle<Object> CompareStrings(
      Isolate* isolate, Handle<JSCollator> collator, Handle<String> s1,
      Handle<String> s2);
 
  // ecma402/#sup-properties-of-the-number-prototype-object
  V8_WARN_UNUSED_RESULT static MaybeHandle<String> NumberToLocaleString(
      Isolate* isolate, Handle<Object> num, Handle<Object> locales,
      Handle<Object> options);
 
  // ecma402/#sec-defaultnumberoption
  V8_WARN_UNUSED_RESULT static Maybe<int> DefaultNumberOption(
      Isolate* isolate, Handle<Object> value, int min, int max, int fallback,
      Handle<String> property);
 
  // ecma402/#sec-getnumberoption
  V8_WARN_UNUSED_RESULT static Maybe<int> GetNumberOption(
      Isolate* isolate, Handle<JSReceiver> options, Handle<String> property,
      int min, int max, int fallback);
  V8_WARN_UNUSED_RESULT static Maybe<int> GetNumberOption(
      Isolate* isolate, Handle<JSReceiver> options, const char* property,
      int min, int max, int fallback);
 
  // ecma402/#sec-setnfdigitoptions
  V8_WARN_UNUSED_RESULT static Maybe<bool> SetNumberFormatDigitOptions(
      Isolate* isolate, icu::DecimalFormat* number_format,
      Handle<JSReceiver> options, int mnfd_default, int mxfd_default);
 
  icu::Locale static CreateICULocale(Isolate* isolate,
                                     Handle<String> bcp47_locale_str);
 
  // Helper funciton to convert a UnicodeString to a Handle<String>
  V8_WARN_UNUSED_RESULT static MaybeHandle<String> ToString(
      Isolate* isolate, const icu::UnicodeString& string);
 
  // Helper function to convert a substring of UnicodeString to a Handle<String>
  V8_WARN_UNUSED_RESULT static MaybeHandle<String> ToString(
      Isolate* isolate, const icu::UnicodeString& string, int32_t begin,
      int32_t end);
 
  // A helper function to implement formatToParts which add element to array as
  // $array[$index] = { type: $field_type_string, value: $value }
  static void AddElement(Isolate* isolate, Handle<JSArray> array, int index,
                         Handle<String> field_type_string,
                         Handle<String> value);
 
  // A helper function to implement formatToParts which add element to array as
  // $array[$index] = {
  //   type: $field_type_string, value: $value,
  //   $additional_property_name: $additional_property_value
  // }
  static void AddElement(Isolate* isolate, Handle<JSArray> array, int index,
                         Handle<String> field_type_string, Handle<String> value,
                         Handle<String> additional_property_name,
                         Handle<String> additional_property_value);
};
 
}  // namespace internal
}  // namespace v8
 
#endif  // V8_OBJECTS_INTL_OBJECTS_H_