1b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Copyright 2013 the V8 project authors. All rights reserved.
2b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// found in the LICENSE file.
4b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
5b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// ECMAScript 402 API implementation.
6b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
7b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
8b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Intl object is a single object that has some named properties,
9b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * all of which are constructors.
10b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
11014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch(function(global, utils) {
12b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
13014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch"use strict";
14b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
15014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch%CheckIsBootstrapping();
16014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
17014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// -------------------------------------------------------------------
18014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// Imports
19014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
20014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar ArrayIndexOf;
21014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar ArrayJoin;
22014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar ArrayPush;
23537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdochvar FLAG_intl_extra;
24014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar GlobalDate = global.Date;
25014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar GlobalNumber = global.Number;
26014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar GlobalRegExp = global.RegExp;
27014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar GlobalString = global.String;
281b268ca467c924004286c97bac133db489cf43d0Ben Murdochvar InstallFunctions = utils.InstallFunctions;
291b268ca467c924004286c97bac133db489cf43d0Ben Murdochvar InstallGetter = utils.InstallGetter;
30537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdochvar InternalArray = utils.InternalArray;
311b268ca467c924004286c97bac133db489cf43d0Ben Murdochvar InternalRegExpMatch;
321b268ca467c924004286c97bac133db489cf43d0Ben Murdochvar InternalRegExpReplace
331b268ca467c924004286c97bac133db489cf43d0Ben Murdochvar IsNaN;
34014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar MakeError;
35014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar MakeRangeError;
36014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar MakeTypeError;
371b268ca467c924004286c97bac133db489cf43d0Ben Murdochvar ObjectHasOwnProperty = utils.ImportNow("ObjectHasOwnProperty");
381b268ca467c924004286c97bac133db489cf43d0Ben Murdochvar OverrideFunction = utils.OverrideFunction;
39014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar patternSymbol = utils.ImportNow("intl_pattern_symbol");
40014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar resolvedSymbol = utils.ImportNow("intl_resolved_symbol");
411b268ca467c924004286c97bac133db489cf43d0Ben Murdochvar SetFunctionName = utils.SetFunctionName;
42014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar StringIndexOf;
43014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar StringLastIndexOf;
44014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar StringSplit;
45014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar StringSubstr;
46014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar StringSubstring;
47014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
48014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochutils.Import(function(from) {
49014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  ArrayIndexOf = from.ArrayIndexOf;
50014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  ArrayJoin = from.ArrayJoin;
51014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  ArrayPush = from.ArrayPush;
52014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  IsNaN = from.IsNaN;
53014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  MakeError = from.MakeError;
54014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  MakeRangeError = from.MakeRangeError;
55014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  MakeTypeError = from.MakeTypeError;
561b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  InternalRegExpMatch = from.InternalRegExpMatch;
571b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  InternalRegExpReplace = from.InternalRegExpReplace;
58014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  StringIndexOf = from.StringIndexOf;
59014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  StringLastIndexOf = from.StringLastIndexOf;
60014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  StringSplit = from.StringSplit;
61014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  StringSubstr = from.StringSubstr;
62014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  StringSubstring = from.StringSubstring;
63014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch});
64014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
65537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdochutils.ImportFromExperimental(function(from) {
66537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  FLAG_intl_extra = from.FLAG_intl_extra;
67537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch});
68537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch
691b268ca467c924004286c97bac133db489cf43d0Ben Murdoch// Utilities for definitions
701b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
711b268ca467c924004286c97bac133db489cf43d0Ben Murdochfunction InstallFunction(object, name, func) {
721b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  InstallFunctions(object, DONT_ENUM, [name, func]);
731b268ca467c924004286c97bac133db489cf43d0Ben Murdoch}
741b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
751b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
761b268ca467c924004286c97bac133db489cf43d0Ben Murdochfunction InstallConstructor(object, name, func) {
771b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  %CheckIsBootstrapping();
781b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  SetFunctionName(func, name);
791b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  %AddNamedProperty(object, name, func, DONT_ENUM);
801b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  %SetNativeFlag(func);
811b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  %ToFastProperties(object);
821b268ca467c924004286c97bac133db489cf43d0Ben Murdoch}
831b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
841b268ca467c924004286c97bac133db489cf43d0Ben Murdoch/**
851b268ca467c924004286c97bac133db489cf43d0Ben Murdoch * Adds bound method to the prototype of the given object.
861b268ca467c924004286c97bac133db489cf43d0Ben Murdoch */
87537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdochfunction AddBoundMethod(obj, methodName, implementation, length, type) {
881b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  %CheckIsBootstrapping();
891b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  var internalName = %CreatePrivateSymbol(methodName);
901b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  var getter = function() {
91537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch    if (!%IsInitializedIntlObjectOfType(this, type)) {
921b268ca467c924004286c97bac133db489cf43d0Ben Murdoch      throw MakeTypeError(kMethodCalledOnWrongObject, methodName);
931b268ca467c924004286c97bac133db489cf43d0Ben Murdoch    }
941b268ca467c924004286c97bac133db489cf43d0Ben Murdoch    if (IS_UNDEFINED(this[internalName])) {
951b268ca467c924004286c97bac133db489cf43d0Ben Murdoch      var boundMethod;
961b268ca467c924004286c97bac133db489cf43d0Ben Murdoch      if (IS_UNDEFINED(length) || length === 2) {
971b268ca467c924004286c97bac133db489cf43d0Ben Murdoch        boundMethod = (x, y) => implementation(this, x, y);
981b268ca467c924004286c97bac133db489cf43d0Ben Murdoch      } else if (length === 1) {
991b268ca467c924004286c97bac133db489cf43d0Ben Murdoch        boundMethod = x => implementation(this, x);
1001b268ca467c924004286c97bac133db489cf43d0Ben Murdoch      } else {
1011b268ca467c924004286c97bac133db489cf43d0Ben Murdoch        boundMethod = (...args) => {
1021b268ca467c924004286c97bac133db489cf43d0Ben Murdoch          // DateTimeFormat.format needs to be 0 arg method, but can stil
1031b268ca467c924004286c97bac133db489cf43d0Ben Murdoch          // receive optional dateValue param. If one was provided, pass it
1041b268ca467c924004286c97bac133db489cf43d0Ben Murdoch          // along.
1051b268ca467c924004286c97bac133db489cf43d0Ben Murdoch          if (args.length > 0) {
1061b268ca467c924004286c97bac133db489cf43d0Ben Murdoch            return implementation(this, args[0]);
1071b268ca467c924004286c97bac133db489cf43d0Ben Murdoch          } else {
1081b268ca467c924004286c97bac133db489cf43d0Ben Murdoch            return implementation(this);
1091b268ca467c924004286c97bac133db489cf43d0Ben Murdoch          }
1101b268ca467c924004286c97bac133db489cf43d0Ben Murdoch        }
1111b268ca467c924004286c97bac133db489cf43d0Ben Murdoch      }
1121b268ca467c924004286c97bac133db489cf43d0Ben Murdoch      // TODO(littledan): Once function name reform is shipped, remove the
1131b268ca467c924004286c97bac133db489cf43d0Ben Murdoch      // following line and wrap the boundMethod definition in an anonymous
1141b268ca467c924004286c97bac133db489cf43d0Ben Murdoch      // function macro.
1151b268ca467c924004286c97bac133db489cf43d0Ben Murdoch      %FunctionSetName(boundMethod, '__bound' + methodName + '__');
1161b268ca467c924004286c97bac133db489cf43d0Ben Murdoch      %FunctionRemovePrototype(boundMethod);
1171b268ca467c924004286c97bac133db489cf43d0Ben Murdoch      %SetNativeFlag(boundMethod);
1181b268ca467c924004286c97bac133db489cf43d0Ben Murdoch      this[internalName] = boundMethod;
1191b268ca467c924004286c97bac133db489cf43d0Ben Murdoch    }
1201b268ca467c924004286c97bac133db489cf43d0Ben Murdoch    return this[internalName];
1211b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  };
1221b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
1231b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  InstallGetter(obj.prototype, methodName, getter, DONT_ENUM);
1241b268ca467c924004286c97bac133db489cf43d0Ben Murdoch}
1251b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
126014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// -------------------------------------------------------------------
127b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
128014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar Intl = {};
129b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
130014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch%AddNamedProperty(global, "Intl", Intl, DONT_ENUM);
131b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
132b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
133b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Caches available locales for each service.
134b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
135b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvar AVAILABLE_LOCALES = {
136014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  'collator': UNDEFINED,
137014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  'numberformat': UNDEFINED,
138014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  'dateformat': UNDEFINED,
139014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  'breakiterator': UNDEFINED
140b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch};
141b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
142b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
143b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Caches default ICU locale.
144b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
145014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar DEFAULT_ICU_LOCALE = UNDEFINED;
146b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
147537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdochfunction GetDefaultICULocaleJS() {
148537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  if (IS_UNDEFINED(DEFAULT_ICU_LOCALE)) {
149537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch    DEFAULT_ICU_LOCALE = %GetDefaultICULocale();
150537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  }
151537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  return DEFAULT_ICU_LOCALE;
152537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch}
153537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch
154b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
155b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Unicode extension regular expression.
156b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
157014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar UNICODE_EXTENSION_RE = UNDEFINED;
158b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
159b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction GetUnicodeExtensionRE() {
160014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (IS_UNDEFINED(UNDEFINED)) {
161014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    UNICODE_EXTENSION_RE = new GlobalRegExp('-u(-[a-z0-9]{2,8})+', 'g');
162b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
163b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return UNICODE_EXTENSION_RE;
164b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
165b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
166b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
167b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Matches any Unicode extension.
168b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
169014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar ANY_EXTENSION_RE = UNDEFINED;
170b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
171b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction GetAnyExtensionRE() {
172014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (IS_UNDEFINED(ANY_EXTENSION_RE)) {
173014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    ANY_EXTENSION_RE = new GlobalRegExp('-[a-z0-9]{1}-.*', 'g');
174b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
175b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return ANY_EXTENSION_RE;
176b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
177b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
178b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
179b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Replace quoted text (single quote, anything but the quote and quote again).
180b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
181014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar QUOTED_STRING_RE = UNDEFINED;
182b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
183b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction GetQuotedStringRE() {
184014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (IS_UNDEFINED(QUOTED_STRING_RE)) {
185014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    QUOTED_STRING_RE = new GlobalRegExp("'[^']+'", 'g');
186b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
187b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return QUOTED_STRING_RE;
188b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
189b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
190b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
191b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Matches valid service name.
192b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
193014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar SERVICE_RE = UNDEFINED;
194b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
195b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction GetServiceRE() {
196014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (IS_UNDEFINED(SERVICE_RE)) {
197b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    SERVICE_RE =
198014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        new GlobalRegExp('^(collator|numberformat|dateformat|breakiterator)$');
199b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
200b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return SERVICE_RE;
201b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
202b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
203b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
204b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Validates a language tag against bcp47 spec.
205b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Actual value is assigned on first run.
206b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
207014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar LANGUAGE_TAG_RE = UNDEFINED;
208b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
209b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction GetLanguageTagRE() {
210014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (IS_UNDEFINED(LANGUAGE_TAG_RE)) {
211b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    BuildLanguageTagREs();
212b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
213b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return LANGUAGE_TAG_RE;
214b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
215b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
216b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
217b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Helps find duplicate variants in the language tag.
218b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
219014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar LANGUAGE_VARIANT_RE = UNDEFINED;
220b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
221b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction GetLanguageVariantRE() {
222014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (IS_UNDEFINED(LANGUAGE_VARIANT_RE)) {
223b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    BuildLanguageTagREs();
224b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
225b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return LANGUAGE_VARIANT_RE;
226b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
227b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
228b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
229b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Helps find duplicate singletons in the language tag.
230b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
231014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar LANGUAGE_SINGLETON_RE = UNDEFINED;
232b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
233b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction GetLanguageSingletonRE() {
234014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (IS_UNDEFINED(LANGUAGE_SINGLETON_RE)) {
235b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    BuildLanguageTagREs();
236b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
237b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return LANGUAGE_SINGLETON_RE;
238b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
239b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
240b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
241b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Matches valid IANA time zone names.
242b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
243014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar TIMEZONE_NAME_CHECK_RE = UNDEFINED;
244b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
245b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction GetTimezoneNameCheckRE() {
246014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (IS_UNDEFINED(TIMEZONE_NAME_CHECK_RE)) {
247014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    TIMEZONE_NAME_CHECK_RE = new GlobalRegExp(
248014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        '^([A-Za-z]+)/([A-Za-z_-]+)((?:\/[A-Za-z_-]+)+)*$');
249b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
250b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return TIMEZONE_NAME_CHECK_RE;
251b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
252b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
253b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
254014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch * Matches valid location parts of IANA time zone names.
255b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
256014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar TIMEZONE_NAME_LOCATION_PART_RE = UNDEFINED;
257b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
258014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochfunction GetTimezoneNameLocationPartRE() {
259014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (IS_UNDEFINED(TIMEZONE_NAME_LOCATION_PART_RE)) {
260014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    TIMEZONE_NAME_LOCATION_PART_RE =
261014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        new GlobalRegExp('^([A-Za-z]+)((?:[_-][A-Za-z]+)+)*$');
262014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
263014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  return TIMEZONE_NAME_LOCATION_PART_RE;
264014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
265b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
266b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
267b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
268b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Returns an intersection of locales and service supported locales.
269b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Parameter locales is treated as a priority list.
270b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
271b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction supportedLocalesOf(service, locales, options) {
2721b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  if (IS_NULL(InternalRegExpMatch(GetServiceRE(), service))) {
273014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    throw MakeError(kWrongServiceType, service);
274b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
275b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
276b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Provide defaults if matcher was not specified.
277014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (IS_UNDEFINED(options)) {
278b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    options = {};
279b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  } else {
280014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    options = TO_OBJECT(options);
281b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
282b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
283b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var matcher = options.localeMatcher;
284014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (!IS_UNDEFINED(matcher)) {
28521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch    matcher = TO_STRING(matcher);
286b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (matcher !== 'lookup' && matcher !== 'best fit') {
287014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      throw MakeRangeError(kLocaleMatcher, matcher);
288b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
289b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  } else {
290b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    matcher = 'best fit';
291b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
292b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
293b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var requestedLocales = initializeLocaleList(locales);
294b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
295b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Cache these, they don't ever change per service.
296014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (IS_UNDEFINED(AVAILABLE_LOCALES[service])) {
297b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    AVAILABLE_LOCALES[service] = getAvailableLocalesOf(service);
298b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
299b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
300b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Use either best fit or lookup algorithm to match locales.
301b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (matcher === 'best fit') {
302b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return initializeLocaleList(bestFitSupportedLocalesOf(
303b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        requestedLocales, AVAILABLE_LOCALES[service]));
304b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
305b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
306b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return initializeLocaleList(lookupSupportedLocalesOf(
307b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      requestedLocales, AVAILABLE_LOCALES[service]));
308b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
309b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
310b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
311b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
312b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Returns the subset of the provided BCP 47 language priority list for which
313b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * this service has a matching locale when using the BCP 47 Lookup algorithm.
314b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Locales appear in the same order in the returned list as in the input list.
315b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
316b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction lookupSupportedLocalesOf(requestedLocales, availableLocales) {
317537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  var matchedLocales = new InternalArray();
318b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  for (var i = 0; i < requestedLocales.length; ++i) {
319b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Remove -u- extension.
3201b268ca467c924004286c97bac133db489cf43d0Ben Murdoch    var locale = InternalRegExpReplace(
3211b268ca467c924004286c97bac133db489cf43d0Ben Murdoch        GetUnicodeExtensionRE(), requestedLocales[i], '');
322b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    do {
323014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      if (!IS_UNDEFINED(availableLocales[locale])) {
324b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        // Push requested locale not the resolved one.
325014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        %_Call(ArrayPush, matchedLocales, requestedLocales[i]);
326b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        break;
327b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      }
328b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      // Truncate locale if possible, if not break.
329014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      var pos = %_Call(StringLastIndexOf, locale, '-');
330b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if (pos === -1) {
331b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        break;
332b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      }
333014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      locale = %_Call(StringSubstring, locale, 0, pos);
334b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    } while (true);
335b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
336b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
337b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return matchedLocales;
338b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
339b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
340b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
341b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
342b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Returns the subset of the provided BCP 47 language priority list for which
343b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * this service has a matching locale when using the implementation
344b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * dependent algorithm.
345b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Locales appear in the same order in the returned list as in the input list.
346b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
347b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction bestFitSupportedLocalesOf(requestedLocales, availableLocales) {
348b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // TODO(cira): implement better best fit algorithm.
349b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return lookupSupportedLocalesOf(requestedLocales, availableLocales);
350b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
351b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
352b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
353b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
354b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Returns a getOption function that extracts property value for given
355b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * options object. If property is missing it returns defaultValue. If value
356b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * is out of range for that property it throws RangeError.
357b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
358b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction getGetOption(options, caller) {
359014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (IS_UNDEFINED(options)) throw MakeError(kDefaultOptionsMissing, caller);
360b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
361b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var getOption = function getOption(property, type, values, defaultValue) {
362014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (!IS_UNDEFINED(options[property])) {
363b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var value = options[property];
364b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      switch (type) {
365b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        case 'boolean':
36621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch          value = TO_BOOLEAN(value);
367b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch          break;
368b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        case 'string':
36921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch          value = TO_STRING(value);
370b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch          break;
371b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        case 'number':
37221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch          value = TO_NUMBER(value);
373b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch          break;
374b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        default:
375014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch          throw MakeError(kWrongValueType);
376b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      }
377014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
378014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      if (!IS_UNDEFINED(values) && %_Call(ArrayIndexOf, values, value) === -1) {
379014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        throw MakeRangeError(kValueOutOfRange, value, caller, property);
380b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      }
381b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
382b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      return value;
383b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
384b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
385b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return defaultValue;
386b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
387b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
388b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return getOption;
389b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
390b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
391b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
392b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
393b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Compares a BCP 47 language priority list requestedLocales against the locales
394b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * in availableLocales and determines the best available language to meet the
395b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * request. Two algorithms are available to match the locales: the Lookup
396b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * algorithm described in RFC 4647 section 3.4, and an implementation dependent
397b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * best-fit algorithm. Independent of the locale matching algorithm, options
398b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * specified through Unicode locale extension sequences are negotiated
399b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * separately, taking the caller's relevant extension keys and locale data as
400b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * well as client-provided options into consideration. Returns an object with
401b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * a locale property whose value is the language tag of the selected locale,
402b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * and properties for each key in relevantExtensionKeys providing the selected
403b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * value for that key.
404b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
405b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction resolveLocale(service, requestedLocales, options) {
406b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  requestedLocales = initializeLocaleList(requestedLocales);
407b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
408b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var getOption = getGetOption(options, service);
409b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var matcher = getOption('localeMatcher', 'string',
410b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                          ['lookup', 'best fit'], 'best fit');
411b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var resolved;
412b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (matcher === 'lookup') {
413b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    resolved = lookupMatcher(service, requestedLocales);
414b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  } else {
415b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    resolved = bestFitMatcher(service, requestedLocales);
416b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
417b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
418b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return resolved;
419b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
420b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
421b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
422b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
423b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Returns best matched supported locale and extension info using basic
424b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * lookup algorithm.
425b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
426b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction lookupMatcher(service, requestedLocales) {
4271b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  if (IS_NULL(InternalRegExpMatch(GetServiceRE(), service))) {
428014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    throw MakeError(kWrongServiceType, service);
429b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
430b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
431b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Cache these, they don't ever change per service.
432014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (IS_UNDEFINED(AVAILABLE_LOCALES[service])) {
433b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    AVAILABLE_LOCALES[service] = getAvailableLocalesOf(service);
434b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
435b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
436b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  for (var i = 0; i < requestedLocales.length; ++i) {
437b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Remove all extensions.
4381b268ca467c924004286c97bac133db489cf43d0Ben Murdoch    var locale = InternalRegExpReplace(
4391b268ca467c924004286c97bac133db489cf43d0Ben Murdoch        GetAnyExtensionRE(), requestedLocales[i], '');
440b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    do {
441014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      if (!IS_UNDEFINED(AVAILABLE_LOCALES[service][locale])) {
442b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        // Return the resolved locale and extension.
4431b268ca467c924004286c97bac133db489cf43d0Ben Murdoch        var extensionMatch = InternalRegExpMatch(
4441b268ca467c924004286c97bac133db489cf43d0Ben Murdoch            GetUnicodeExtensionRE(), requestedLocales[i]);
445b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        var extension = IS_NULL(extensionMatch) ? '' : extensionMatch[0];
446b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        return {'locale': locale, 'extension': extension, 'position': i};
447b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      }
448b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      // Truncate locale if possible.
449014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      var pos = %_Call(StringLastIndexOf, locale, '-');
450b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if (pos === -1) {
451b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        break;
452b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      }
453014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      locale = %_Call(StringSubstring, locale, 0, pos);
454b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    } while (true);
455b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
456b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
457b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Didn't find a match, return default.
458537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  return {'locale': GetDefaultICULocaleJS(), 'extension': '', 'position': -1};
459b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
460b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
461b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
462b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
463b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Returns best matched supported locale and extension info using
464b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * implementation dependend algorithm.
465b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
466b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction bestFitMatcher(service, requestedLocales) {
467b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // TODO(cira): implement better best fit algorithm.
468b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return lookupMatcher(service, requestedLocales);
469b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
470b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
471b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
472b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
473b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Parses Unicode extension into key - value map.
474b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Returns empty object if the extension string is invalid.
475b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * We are not concerned with the validity of the values at this point.
476b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
477b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction parseExtension(extension) {
478014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  var extensionSplit = %_Call(StringSplit, extension, '-');
479b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
480b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Assume ['', 'u', ...] input, but don't throw.
481b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (extensionSplit.length <= 2 ||
482b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      (extensionSplit[0] !== '' && extensionSplit[1] !== 'u')) {
483b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return {};
484b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
485b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
486b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Key is {2}alphanum, value is {3,8}alphanum.
487b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Some keys may not have explicit values (booleans).
488b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var extensionMap = {};
489014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  var previousKey = UNDEFINED;
490b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  for (var i = 2; i < extensionSplit.length; ++i) {
491b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var length = extensionSplit[i].length;
492b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var element = extensionSplit[i];
493b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (length === 2) {
494014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      extensionMap[element] = UNDEFINED;
495b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      previousKey = element;
496014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    } else if (length >= 3 && length <=8 && !IS_UNDEFINED(previousKey)) {
497b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      extensionMap[previousKey] = element;
498014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      previousKey = UNDEFINED;
499b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    } else {
500b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      // There is a value that's too long, or that doesn't have a key.
501b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      return {};
502b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
503b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
504b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
505b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return extensionMap;
506b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
507b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
508b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
509b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
510b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Populates internalOptions object with boolean key-value pairs
511b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * from extensionMap and options.
512b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Returns filtered extension (number and date format constructors use
513b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Unicode extensions for passing parameters to ICU).
514b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * It's used for extension-option pairs only, e.g. kn-normalization, but not
515b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * for 'sensitivity' since it doesn't have extension equivalent.
516b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Extensions like nu and ca don't have options equivalent, so we place
517b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * undefined in the map.property to denote that.
518b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
519b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction setOptions(inOptions, extensionMap, keyValues, getOption, outOptions) {
520b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var extension = '';
521b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
522b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var updateExtension = function updateExtension(key, value) {
52321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch    return '-' + key + '-' + TO_STRING(value);
524b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
525b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
526b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var updateProperty = function updateProperty(property, type, value) {
527b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (type === 'boolean' && (typeof value === 'string')) {
528b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      value = (value === 'true') ? true : false;
529b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
530b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
531014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (!IS_UNDEFINED(property)) {
532b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      defineWEProperty(outOptions, property, value);
533b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
534b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
535b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
536b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  for (var key in keyValues) {
5371b268ca467c924004286c97bac133db489cf43d0Ben Murdoch    if (HAS_OWN_PROPERTY(keyValues, key)) {
538014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      var value = UNDEFINED;
539b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      var map = keyValues[key];
540014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      if (!IS_UNDEFINED(map.property)) {
541b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        // This may return true if user specifies numeric: 'false', since
542b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        // Boolean('nonempty') === true.
543b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        value = getOption(map.property, map.type, map.values);
544b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      }
545014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      if (!IS_UNDEFINED(value)) {
546b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        updateProperty(map.property, map.type, value);
547b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        extension += updateExtension(key, value);
548b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        continue;
549b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      }
550b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      // User options didn't have it, check Unicode extension.
551b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      // Here we want to convert strings 'true', 'false' into proper Boolean
552b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      // values (not a user error).
5531b268ca467c924004286c97bac133db489cf43d0Ben Murdoch      if (HAS_OWN_PROPERTY(extensionMap, key)) {
554b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        value = extensionMap[key];
555014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        if (!IS_UNDEFINED(value)) {
556b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch          updateProperty(map.property, map.type, value);
557b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch          extension += updateExtension(key, value);
558b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        } else if (map.type === 'boolean') {
559b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch          // Boolean keys are allowed not to have values in Unicode extension.
560b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch          // Those default to true.
561b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch          updateProperty(map.property, map.type, true);
562b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch          extension += updateExtension(key, true);
563b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        }
564b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      }
565b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
566b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
567b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
568b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return extension === ''? '' : '-u' + extension;
569b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
570b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
571b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
572b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
573537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch * Given an array-like, outputs an Array with the numbered
574537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch * properties copied over and defined
575b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * configurable: false, writable: false, enumerable: true.
576b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
577537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdochfunction freezeArray(input) {
578537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  var array = [];
579537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  var l = input.length;
580014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  for (var i = 0; i < l; i++) {
581537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch    if (i in input) {
582537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch      %object_define_property(array, i, {value: input[i],
583537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch                                         configurable: false,
584537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch                                         writable: false,
585537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch                                         enumerable: true});
586014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
587014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
588b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
589537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  %object_define_property(array, 'length', {value: l, writable: false});
590b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return array;
591b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
592b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
593b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
594b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
595b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * It's sometimes desireable to leave user requested locale instead of ICU
596b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * supported one (zh-TW is equivalent to zh-Hant-TW, so we should keep shorter
597b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * one, if that was what user requested).
598b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * This function returns user specified tag if its maximized form matches ICU
599b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * resolved locale. If not we return ICU result.
600b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
601b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction getOptimalLanguageTag(original, resolved) {
602b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Returns Array<Object>, where each object has maximized and base properties.
603b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Maximized: zh -> zh-Hans-CN
604b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Base: zh-CN-u-ca-gregory -> zh-CN
605b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Take care of grandfathered or simple cases.
606b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (original === resolved) {
607b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return original;
608b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
609b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
610b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var locales = %GetLanguageTagVariants([original, resolved]);
611b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (locales[0].maximized !== locales[1].maximized) {
612b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return resolved;
613b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
614b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
615b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Preserve extensions of resolved locale, but swap base tags with original.
6161b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  var resolvedBase = new GlobalRegExp('^' + locales[1].base, 'g');
6171b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  return InternalRegExpReplace(resolvedBase, resolved, locales[0].base);
618b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
619b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
620b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
621b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
622b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Returns an Object that contains all of supported locales for a given
623b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * service.
624b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * In addition to the supported locales we add xx-ZZ locale for each xx-Yyyy-ZZ
625b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * that is supported. This is required by the spec.
626b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
627b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction getAvailableLocalesOf(service) {
628b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var available = %AvailableLocalesOf(service);
629b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
630b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  for (var i in available) {
6311b268ca467c924004286c97bac133db489cf43d0Ben Murdoch    if (HAS_OWN_PROPERTY(available, i)) {
6321b268ca467c924004286c97bac133db489cf43d0Ben Murdoch      var parts = InternalRegExpMatch(
6331b268ca467c924004286c97bac133db489cf43d0Ben Murdoch          /^([a-z]{2,3})-([A-Z][a-z]{3})-([A-Z]{2})$/, i);
6341b268ca467c924004286c97bac133db489cf43d0Ben Murdoch      if (!IS_NULL(parts)) {
635b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        // Build xx-ZZ. We don't care about the actual value,
636b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        // as long it's not undefined.
637b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        available[parts[1] + '-' + parts[3]] = null;
638b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      }
639b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
640b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
641b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
642b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return available;
643b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
644b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
645b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
646b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
647b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Defines a property and sets writable and enumerable to true.
648b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Configurable is false by default.
649b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
650b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction defineWEProperty(object, property, value) {
651537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  %object_define_property(object, property,
652537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch                          {value: value, writable: true, enumerable: true});
653b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
654b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
655b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
656b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
657b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Adds property to an object if the value is not undefined.
658b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Sets configurable descriptor to false.
659b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
660b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction addWEPropertyIfDefined(object, property, value) {
661014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (!IS_UNDEFINED(value)) {
662b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    defineWEProperty(object, property, value);
663b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
664b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
665b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
666b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
667b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
668b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Defines a property and sets writable, enumerable and configurable to true.
669b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
670b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction defineWECProperty(object, property, value) {
671537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  %object_define_property(object, property, {value: value,
672537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch                                             writable: true,
673537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch                                             enumerable: true,
674537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch                                             configurable: true});
675b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
676b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
677b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
678b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
679b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Adds property to an object if the value is not undefined.
680b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Sets all descriptors to true.
681b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
682b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction addWECPropertyIfDefined(object, property, value) {
683014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (!IS_UNDEFINED(value)) {
684b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    defineWECProperty(object, property, value);
685b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
686b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
687b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
688b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
689b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
690b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Returns titlecased word, aMeRricA -> America.
691b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
692b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction toTitleCaseWord(word) {
693014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  return %StringToUpperCase(%_Call(StringSubstr, word, 0, 1)) +
694014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch         %StringToLowerCase(%_Call(StringSubstr, word, 1));
695014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
696014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
697014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch/**
698014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch * Returns titlecased location, bueNos_airES -> Buenos_Aires
699014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch * or ho_cHi_minH -> Ho_Chi_Minh. It is locale-agnostic and only
700014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch * deals with ASCII only characters.
701014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch * 'of', 'au' and 'es' are special-cased and lowercased.
702014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch */
703014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochfunction toTitleCaseTimezoneLocation(location) {
7041b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  var match = InternalRegExpMatch(GetTimezoneNameLocationPartRE(), location)
705014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (IS_NULL(match)) throw MakeRangeError(kExpectedLocation, location);
706014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
707014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  var result = toTitleCaseWord(match[1]);
708014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (!IS_UNDEFINED(match[2]) && 2 < match.length) {
709014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // The first character is a separator, '_' or '-'.
710014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // None of IANA zone names has both '_' and '-'.
711014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    var separator = %_Call(StringSubstring, match[2], 0, 1);
712014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    var parts = %_Call(StringSplit, match[2], separator);
713014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    for (var i = 1; i < parts.length; i++) {
714014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      var part = parts[i]
715014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      var lowercasedPart = %StringToLowerCase(part);
716014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      result = result + separator +
717014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch          ((lowercasedPart !== 'es' &&
718014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch            lowercasedPart !== 'of' && lowercasedPart !== 'au') ?
719014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch          toTitleCaseWord(part) : lowercasedPart);
720014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
721014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
722014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  return result;
723b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
724b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
725b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
726b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Canonicalizes the language tag, or throws in case the tag is invalid.
727b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
728b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction canonicalizeLanguageTag(localeID) {
729b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // null is typeof 'object' so we have to do extra check.
730537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  if ((!IS_STRING(localeID) && !IS_RECEIVER(localeID)) ||
731b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      IS_NULL(localeID)) {
732014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    throw MakeTypeError(kLanguageID);
733b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
734b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
735537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  // Optimize for the most common case; a language code alone in
736537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  // the canonical form/lowercase (e.g. "en", "fil").
737537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  if (IS_STRING(localeID) &&
738537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch      !IS_NULL(InternalRegExpMatch(/^[a-z]{2,3}$/, localeID))) {
739537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch    return localeID;
740537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  }
741537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch
74221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  var localeString = TO_STRING(localeID);
743b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
744b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (isValidLanguageTag(localeString) === false) {
745014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    throw MakeRangeError(kInvalidLanguageTag, localeString);
746b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
747b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
748b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var tag = %CanonicalizeLanguageTag(localeString);
749b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (tag === 'invalid-tag') {
750014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    throw MakeRangeError(kInvalidLanguageTag, localeString);
751b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
752b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
753b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return tag;
754b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
755b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
756b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
757b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
758b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Returns an array where all locales are canonicalized and duplicates removed.
759b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Throws on locales that are not well formed BCP47 tags.
760b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
761b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction initializeLocaleList(locales) {
762537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  var seen = new InternalArray();
763537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  if (!IS_UNDEFINED(locales)) {
764b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // We allow single string localeID.
765b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (typeof locales === 'string') {
766014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      %_Call(ArrayPush, seen, canonicalizeLanguageTag(locales));
767b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      return freezeArray(seen);
768b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
769b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
770014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    var o = TO_OBJECT(locales);
771014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    var len = TO_UINT32(o.length);
772b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
773b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    for (var k = 0; k < len; k++) {
774b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if (k in o) {
775b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        var value = o[k];
776b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
777b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        var tag = canonicalizeLanguageTag(value);
778b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
779014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        if (%_Call(ArrayIndexOf, seen, tag) === -1) {
780014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch          %_Call(ArrayPush, seen, tag);
781b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        }
782b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      }
783b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
784b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
785b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
786b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return freezeArray(seen);
787b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
788b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
789b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
790b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
791b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Validates the language tag. Section 2.2.9 of the bcp47 spec
792b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * defines a valid tag.
793b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch *
794b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * ICU is too permissible and lets invalid tags, like
795b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * hant-cmn-cn, through.
796b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch *
797b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Returns false if the language tag is invalid.
798b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
799b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction isValidLanguageTag(locale) {
800b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Check if it's well-formed, including grandfadered tags.
8011b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  if (IS_NULL(InternalRegExpMatch(GetLanguageTagRE(), locale))) {
802b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return false;
803b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
804b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
805b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Just return if it's a x- form. It's all private.
806014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (%_Call(StringIndexOf, locale, 'x-') === 0) {
807b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return true;
808b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
809b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
810b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Check if there are any duplicate variants or singletons (extensions).
811b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
812b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Remove private use section.
8131b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  locale = %_Call(StringSplit, locale, '-x-')[0];
814b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
815b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Skip language since it can match variant regex, so we start from 1.
816b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // We are matching i-klingon here, but that's ok, since i-klingon-klingon
817b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // is not valid and would fail LANGUAGE_TAG_RE test.
818537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  var variants = new InternalArray();
819537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  var extensions = new InternalArray();
8201b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  var parts = %_Call(StringSplit, locale, '-');
821b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  for (var i = 1; i < parts.length; i++) {
822b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var value = parts[i];
8231b268ca467c924004286c97bac133db489cf43d0Ben Murdoch    if (!IS_NULL(InternalRegExpMatch(GetLanguageVariantRE(), value)) &&
824014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        extensions.length === 0) {
825014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      if (%_Call(ArrayIndexOf, variants, value) === -1) {
826014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        %_Call(ArrayPush, variants, value);
827b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      } else {
828b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        return false;
829b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      }
830b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
831b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
8321b268ca467c924004286c97bac133db489cf43d0Ben Murdoch    if (!IS_NULL(InternalRegExpMatch(GetLanguageSingletonRE(), value))) {
833014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      if (%_Call(ArrayIndexOf, extensions, value) === -1) {
834014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        %_Call(ArrayPush, extensions, value);
835b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      } else {
836b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        return false;
837b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      }
838b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
839b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
840b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
841b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return true;
842b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch }
843b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
844b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
845b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
846b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Builds a regular expresion that validates the language tag
847b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * against bcp47 spec.
848b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Uses http://tools.ietf.org/html/bcp47, section 2.1, ABNF.
849b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Runs on load and initializes the global REs.
850b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
851b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction BuildLanguageTagREs() {
852b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var alpha = '[a-zA-Z]';
853b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var digit = '[0-9]';
854b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var alphanum = '(' + alpha + '|' + digit + ')';
855b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var regular = '(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|' +
856b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                'zh-min|zh-min-nan|zh-xiang)';
857b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var irregular = '(en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|' +
858b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                  'i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tay|' +
859b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                  'i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)';
860b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var grandfathered = '(' + irregular + '|' + regular + ')';
861b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var privateUse = '(x(-' + alphanum + '{1,8})+)';
862b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
863b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var singleton = '(' + digit + '|[A-WY-Za-wy-z])';
864014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  LANGUAGE_SINGLETON_RE = new GlobalRegExp('^' + singleton + '$', 'i');
865b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
866b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var extension = '(' + singleton + '(-' + alphanum + '{2,8})+)';
867b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
868b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var variant = '(' + alphanum + '{5,8}|(' + digit + alphanum + '{3}))';
869014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  LANGUAGE_VARIANT_RE = new GlobalRegExp('^' + variant + '$', 'i');
870b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
871b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var region = '(' + alpha + '{2}|' + digit + '{3})';
872b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var script = '(' + alpha + '{4})';
873b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var extLang = '(' + alpha + '{3}(-' + alpha + '{3}){0,2})';
874b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var language = '(' + alpha + '{2,3}(-' + extLang + ')?|' + alpha + '{4}|' +
875b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                 alpha + '{5,8})';
876b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var langTag = language + '(-' + script + ')?(-' + region + ')?(-' +
877b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                variant + ')*(-' + extension + ')*(-' + privateUse + ')?';
878b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
879b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var languageTag =
880b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      '^(' + langTag + '|' + privateUse + '|' + grandfathered + ')$';
881014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  LANGUAGE_TAG_RE = new GlobalRegExp(languageTag, 'i');
882b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
883b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
884014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar resolvedAccessor = {
885014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  get() {
886014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    %IncrementUseCounter(kIntlResolved);
887014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    return this[resolvedSymbol];
888014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  },
889014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  set(value) {
890014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    this[resolvedSymbol] = value;
891014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
892014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch};
893014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
894b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
895b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Initializes the given object so it's a valid Collator instance.
896b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Useful for subclassing.
897b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
898b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction initializeCollator(collator, locales, options) {
899b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (%IsInitializedIntlObject(collator)) {
900014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    throw MakeTypeError(kReinitializeIntl, "Collator");
901b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
902b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
903014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (IS_UNDEFINED(options)) {
904b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    options = {};
905b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
906b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
907b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var getOption = getGetOption(options, 'collator');
908b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
909b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var internalOptions = {};
910b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
911b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  defineWEProperty(internalOptions, 'usage', getOption(
912b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    'usage', 'string', ['sort', 'search'], 'sort'));
913b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
914b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var sensitivity = getOption('sensitivity', 'string',
915b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                              ['base', 'accent', 'case', 'variant']);
916014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (IS_UNDEFINED(sensitivity) && internalOptions.usage === 'sort') {
917b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    sensitivity = 'variant';
918b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
919b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  defineWEProperty(internalOptions, 'sensitivity', sensitivity);
920b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
921b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  defineWEProperty(internalOptions, 'ignorePunctuation', getOption(
922014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    'ignorePunctuation', 'boolean', UNDEFINED, false));
923b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
924b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var locale = resolveLocale('collator', locales, options);
925b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
926b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // ICU can't take kb, kc... parameters through localeID, so we need to pass
927b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // them as options.
928b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // One exception is -co- which has to be part of the extension, but only for
929b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // usage: sort, and its value can't be 'standard' or 'search'.
930b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var extensionMap = parseExtension(locale.extension);
931014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
932014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  /**
933014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch   * Map of Unicode extensions to option properties, and their values and types,
934014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch   * for a collator.
935014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch   */
936014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  var COLLATOR_KEY_MAP = {
937014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    'kn': {'property': 'numeric', 'type': 'boolean'},
938014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    'kf': {'property': 'caseFirst', 'type': 'string',
939014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch           'values': ['false', 'lower', 'upper']}
940014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  };
941014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
942b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  setOptions(
943b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      options, extensionMap, COLLATOR_KEY_MAP, getOption, internalOptions);
944b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
945b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var collation = 'default';
946b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var extension = '';
9471b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  if (HAS_OWN_PROPERTY(extensionMap, 'co') && internalOptions.usage === 'sort') {
948014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
949014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    /**
950014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch     * Allowed -u-co- values. List taken from:
951014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch     * http://unicode.org/repos/cldr/trunk/common/bcp47/collation.xml
952014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch     */
953014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    var ALLOWED_CO_VALUES = [
954014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      'big5han', 'dict', 'direct', 'ducet', 'gb2312', 'phonebk', 'phonetic',
955014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      'pinyin', 'reformed', 'searchjl', 'stroke', 'trad', 'unihan', 'zhuyin'
956014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    ];
957014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
958014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (%_Call(ArrayIndexOf, ALLOWED_CO_VALUES, extensionMap.co) !== -1) {
959b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      extension = '-u-co-' + extensionMap.co;
960b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      // ICU can't tell us what the collation is, so save user's input.
961b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      collation = extensionMap.co;
962b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
963b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  } else if (internalOptions.usage === 'search') {
964b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    extension = '-u-co-search';
965b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
966b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  defineWEProperty(internalOptions, 'collation', collation);
967b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
968b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var requestedLocale = locale.locale + extension;
969b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
970b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // We define all properties C++ code may produce, to prevent security
971b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // problems. If malicious user decides to redefine Object.prototype.locale
972b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // we can't just use plain x.locale = 'us' or in C++ Set("locale", "us").
973537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  // %object_define_properties will either succeed defining or throw an error.
974537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  var resolved = %object_define_properties({}, {
975b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    caseFirst: {writable: true},
976b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    collation: {value: internalOptions.collation, writable: true},
977b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    ignorePunctuation: {writable: true},
978b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    locale: {writable: true},
979b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    numeric: {writable: true},
980b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    requestedLocale: {value: requestedLocale, writable: true},
981b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    sensitivity: {writable: true},
982b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    strength: {writable: true},
983b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    usage: {value: internalOptions.usage, writable: true}
984b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  });
985b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
986b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var internalCollator = %CreateCollator(requestedLocale,
987b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                         internalOptions,
988b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                         resolved);
989b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
990b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Writable, configurable and enumerable are set to false by default.
991b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  %MarkAsInitializedIntlObjectOfType(collator, 'collator', internalCollator);
992014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  collator[resolvedSymbol] = resolved;
993537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  if (FLAG_intl_extra) {
994537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch    %object_define_property(collator, 'resolved', resolvedAccessor);
995537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  }
996b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
997b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return collator;
998b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
999b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1000b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1001b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
1002b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Constructs Intl.Collator object given optional locales and options
1003b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * parameters.
1004b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch *
1005b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * @constructor
1006b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
10071b268ca467c924004286c97bac133db489cf43d0Ben MurdochInstallConstructor(Intl, 'Collator', function() {
1008342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    var locales = arguments[0];
1009342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    var options = arguments[1];
1010b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1011b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (!this || this === Intl) {
1012b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      // Constructor is called as a function.
1013b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      return new Intl.Collator(locales, options);
1014b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
1015b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1016014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    return initializeCollator(TO_OBJECT(this), locales, options);
10171b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  }
1018b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch);
1019b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1020b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1021b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
1022b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Collator resolvedOptions method.
1023b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
10241b268ca467c924004286c97bac133db489cf43d0Ben MurdochInstallFunction(Intl.Collator.prototype, 'resolvedOptions', function() {
1025014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (!IS_UNDEFINED(new.target)) {
1026014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
1027b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
1028b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1029b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (!%IsInitializedIntlObjectOfType(this, 'collator')) {
1030014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      throw MakeTypeError(kResolvedOptionsCalledOnNonObject, "Collator");
1031b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
1032b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1033b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var coll = this;
1034014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    var locale = getOptimalLanguageTag(coll[resolvedSymbol].requestedLocale,
1035014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                       coll[resolvedSymbol].locale);
1036b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1037b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return {
1038b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      locale: locale,
1039014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      usage: coll[resolvedSymbol].usage,
1040014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      sensitivity: coll[resolvedSymbol].sensitivity,
1041014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      ignorePunctuation: coll[resolvedSymbol].ignorePunctuation,
1042014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      numeric: coll[resolvedSymbol].numeric,
1043014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      caseFirst: coll[resolvedSymbol].caseFirst,
1044014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      collation: coll[resolvedSymbol].collation
1045b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    };
10461b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  }
1047b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch);
1048b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1049b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1050b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
1051b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Returns the subset of the given locale list for which this locale list
1052b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * has a matching (possibly fallback) locale. Locales appear in the same
1053b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * order in the returned list as in the input list.
1054b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Options are optional parameter.
1055b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
10561b268ca467c924004286c97bac133db489cf43d0Ben MurdochInstallFunction(Intl.Collator, 'supportedLocalesOf', function(locales) {
1057014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (!IS_UNDEFINED(new.target)) {
1058014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
1059b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
1060b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1061342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    return supportedLocalesOf('collator', locales, arguments[1]);
10621b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  }
1063b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch);
1064b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1065b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1066b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
1067b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * When the compare method is called with two arguments x and y, it returns a
1068b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Number other than NaN that represents the result of a locale-sensitive
1069b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * String comparison of x with y.
1070b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * The result is intended to order String values in the sort order specified
1071b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * by the effective locale and collation options computed during construction
1072b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * of this Collator object, and will be negative, zero, or positive, depending
1073b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * on whether x comes before y in the sort order, the Strings are equal under
1074b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * the sort order, or x comes after y in the sort order, respectively.
1075b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
1076b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction compare(collator, x, y) {
1077b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return %InternalCompare(%GetImplFromInitializedIntlObject(collator),
107821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch                          TO_STRING(x), TO_STRING(y));
1079b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch};
1080b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1081b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1082537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben MurdochAddBoundMethod(Intl.Collator, 'compare', compare, 2, 'collator');
1083b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1084b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
1085b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Verifies that the input is a well-formed ISO 4217 currency code.
1086b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Don't uppercase to test. It could convert invalid code into a valid one.
1087b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * For example \u00DFP (Eszett+P) becomes SSP.
1088b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
1089b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction isWellFormedCurrencyCode(currency) {
10901b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  return typeof currency == "string" && currency.length == 3 &&
10911b268ca467c924004286c97bac133db489cf43d0Ben Murdoch      IS_NULL(InternalRegExpMatch(/[^A-Za-z]/, currency));
1092b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1093b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1094b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1095b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
1096b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Returns the valid digit count for a property, or throws RangeError on
1097b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * a value out of the range.
1098b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
1099b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction getNumberOption(options, property, min, max, fallback) {
1100b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var value = options[property];
1101014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (!IS_UNDEFINED(value)) {
110221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch    value = TO_NUMBER(value);
110321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch    if (NUMBER_IS_NAN(value) || value < min || value > max) {
1104014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      throw MakeRangeError(kPropertyValueOutOfRange, property);
1105b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
11061b268ca467c924004286c97bac133db489cf43d0Ben Murdoch    return %math_floor(value);
1107b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1108b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1109b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return fallback;
1110b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1111b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1112014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvar patternAccessor = {
1113014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  get() {
1114014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    %IncrementUseCounter(kIntlPattern);
1115014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    return this[patternSymbol];
1116014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  },
1117014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  set(value) {
1118014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    this[patternSymbol] = value;
1119014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
1120014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch};
1121b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1122b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
1123b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Initializes the given object so it's a valid NumberFormat instance.
1124b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Useful for subclassing.
1125b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
1126b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction initializeNumberFormat(numberFormat, locales, options) {
1127b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (%IsInitializedIntlObject(numberFormat)) {
1128014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    throw MakeTypeError(kReinitializeIntl, "NumberFormat");
1129b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1130b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1131014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (IS_UNDEFINED(options)) {
1132b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    options = {};
1133b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1134b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1135b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var getOption = getGetOption(options, 'numberformat');
1136b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1137b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var locale = resolveLocale('numberformat', locales, options);
1138b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1139b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var internalOptions = {};
1140b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  defineWEProperty(internalOptions, 'style', getOption(
1141b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    'style', 'string', ['decimal', 'percent', 'currency'], 'decimal'));
1142b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1143b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var currency = getOption('currency', 'string');
1144014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (!IS_UNDEFINED(currency) && !isWellFormedCurrencyCode(currency)) {
1145014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    throw MakeRangeError(kInvalidCurrencyCode, currency);
1146b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1147b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1148014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (internalOptions.style === 'currency' && IS_UNDEFINED(currency)) {
1149014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    throw MakeTypeError(kCurrencyCode);
1150b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1151b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1152b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var currencyDisplay = getOption(
1153b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      'currencyDisplay', 'string', ['code', 'symbol', 'name'], 'symbol');
1154b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (internalOptions.style === 'currency') {
1155014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    defineWEProperty(internalOptions, 'currency', %StringToUpperCase(currency));
1156b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    defineWEProperty(internalOptions, 'currencyDisplay', currencyDisplay);
1157b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1158b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1159b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Digit ranges.
1160b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var mnid = getNumberOption(options, 'minimumIntegerDigits', 1, 21, 1);
1161b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  defineWEProperty(internalOptions, 'minimumIntegerDigits', mnid);
1162b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1163014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  var mnfd = options['minimumFractionDigits'];
1164014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  var mxfd = options['maximumFractionDigits'];
1165014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (!IS_UNDEFINED(mnfd) || internalOptions.style !== 'currency') {
1166014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    mnfd = getNumberOption(options, 'minimumFractionDigits', 0, 20, 0);
1167014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    defineWEProperty(internalOptions, 'minimumFractionDigits', mnfd);
1168014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
1169b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1170014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (!IS_UNDEFINED(mxfd) || internalOptions.style !== 'currency') {
1171014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    var min_mxfd = internalOptions.style === 'percent' ? 0 : 3;
1172014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    mnfd = IS_UNDEFINED(mnfd) ? 0 : mnfd;
1173014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    var fallback_limit = (mnfd > min_mxfd) ? mnfd : min_mxfd;
1174014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    mxfd = getNumberOption(options, 'maximumFractionDigits', mnfd, 20, fallback_limit);
1175014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    defineWEProperty(internalOptions, 'maximumFractionDigits', mxfd);
1176014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
1177b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1178b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var mnsd = options['minimumSignificantDigits'];
1179b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var mxsd = options['maximumSignificantDigits'];
1180014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (!IS_UNDEFINED(mnsd) || !IS_UNDEFINED(mxsd)) {
1181b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    mnsd = getNumberOption(options, 'minimumSignificantDigits', 1, 21, 0);
1182b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    defineWEProperty(internalOptions, 'minimumSignificantDigits', mnsd);
1183b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1184b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    mxsd = getNumberOption(options, 'maximumSignificantDigits', mnsd, 21, 21);
1185b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    defineWEProperty(internalOptions, 'maximumSignificantDigits', mxsd);
1186b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1187b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1188b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Grouping.
1189b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  defineWEProperty(internalOptions, 'useGrouping', getOption(
1190014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    'useGrouping', 'boolean', UNDEFINED, true));
1191b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1192b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // ICU prefers options to be passed using -u- extension key/values for
1193b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // number format, so we need to build that.
1194b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var extensionMap = parseExtension(locale.extension);
1195014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1196014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  /**
1197014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch   * Map of Unicode extensions to option properties, and their values and types,
1198014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch   * for a number format.
1199014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch   */
1200014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  var NUMBER_FORMAT_KEY_MAP = {
1201014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    'nu': {'property': UNDEFINED, 'type': 'string'}
1202014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  };
1203014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1204b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var extension = setOptions(options, extensionMap, NUMBER_FORMAT_KEY_MAP,
1205b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                             getOption, internalOptions);
1206b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1207b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var requestedLocale = locale.locale + extension;
1208537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  var resolved = %object_define_properties({}, {
1209b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    currency: {writable: true},
1210b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    currencyDisplay: {writable: true},
1211b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    locale: {writable: true},
1212b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    maximumFractionDigits: {writable: true},
1213b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    minimumFractionDigits: {writable: true},
1214b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    minimumIntegerDigits: {writable: true},
1215b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    numberingSystem: {writable: true},
1216b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    requestedLocale: {value: requestedLocale, writable: true},
1217b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    style: {value: internalOptions.style, writable: true},
1218b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    useGrouping: {writable: true}
1219b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  });
12201b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  if (HAS_OWN_PROPERTY(internalOptions, 'minimumSignificantDigits')) {
1221014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    defineWEProperty(resolved, 'minimumSignificantDigits', UNDEFINED);
1222b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
12231b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  if (HAS_OWN_PROPERTY(internalOptions, 'maximumSignificantDigits')) {
1224014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    defineWEProperty(resolved, 'maximumSignificantDigits', UNDEFINED);
1225b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1226b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var formatter = %CreateNumberFormat(requestedLocale,
1227b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                      internalOptions,
1228b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                      resolved);
1229b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1230b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (internalOptions.style === 'currency') {
1231537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch    %object_define_property(resolved, 'currencyDisplay',
1232537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch        {value: currencyDisplay, writable: true});
1233b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1234b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1235b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  %MarkAsInitializedIntlObjectOfType(numberFormat, 'numberformat', formatter);
1236014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  numberFormat[resolvedSymbol] = resolved;
1237537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  if (FLAG_intl_extra) {
1238537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch    %object_define_property(resolved, 'pattern', patternAccessor);
1239537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch    %object_define_property(numberFormat, 'resolved', resolvedAccessor);
1240537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  }
1241b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1242b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return numberFormat;
1243b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1244b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1245b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1246b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
1247b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Constructs Intl.NumberFormat object given optional locales and options
1248b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * parameters.
1249b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch *
1250b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * @constructor
1251b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
12521b268ca467c924004286c97bac133db489cf43d0Ben MurdochInstallConstructor(Intl, 'NumberFormat', function() {
1253342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    var locales = arguments[0];
1254342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    var options = arguments[1];
1255b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1256b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (!this || this === Intl) {
1257b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      // Constructor is called as a function.
1258b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      return new Intl.NumberFormat(locales, options);
1259b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
1260b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1261014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    return initializeNumberFormat(TO_OBJECT(this), locales, options);
12621b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  }
1263b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch);
1264b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1265b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1266b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
1267b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * NumberFormat resolvedOptions method.
1268b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
12691b268ca467c924004286c97bac133db489cf43d0Ben MurdochInstallFunction(Intl.NumberFormat.prototype, 'resolvedOptions', function() {
1270014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (!IS_UNDEFINED(new.target)) {
1271014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
1272b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
1273b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1274b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (!%IsInitializedIntlObjectOfType(this, 'numberformat')) {
1275014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      throw MakeTypeError(kResolvedOptionsCalledOnNonObject, "NumberFormat");
1276b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
1277b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1278b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var format = this;
1279014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    var locale = getOptimalLanguageTag(format[resolvedSymbol].requestedLocale,
1280014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                       format[resolvedSymbol].locale);
1281b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1282b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var result = {
1283b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      locale: locale,
1284014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      numberingSystem: format[resolvedSymbol].numberingSystem,
1285014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      style: format[resolvedSymbol].style,
1286014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      useGrouping: format[resolvedSymbol].useGrouping,
1287014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      minimumIntegerDigits: format[resolvedSymbol].minimumIntegerDigits,
1288014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      minimumFractionDigits: format[resolvedSymbol].minimumFractionDigits,
1289014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      maximumFractionDigits: format[resolvedSymbol].maximumFractionDigits,
1290b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    };
1291b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1292b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (result.style === 'currency') {
1293014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      defineWECProperty(result, 'currency', format[resolvedSymbol].currency);
1294b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      defineWECProperty(result, 'currencyDisplay',
1295014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                        format[resolvedSymbol].currencyDisplay);
1296b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
1297b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
12981b268ca467c924004286c97bac133db489cf43d0Ben Murdoch    if (HAS_OWN_PROPERTY(format[resolvedSymbol], 'minimumSignificantDigits')) {
1299b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      defineWECProperty(result, 'minimumSignificantDigits',
1300014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                        format[resolvedSymbol].minimumSignificantDigits);
1301b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
1302b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
13031b268ca467c924004286c97bac133db489cf43d0Ben Murdoch    if (HAS_OWN_PROPERTY(format[resolvedSymbol], 'maximumSignificantDigits')) {
1304b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      defineWECProperty(result, 'maximumSignificantDigits',
1305014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                        format[resolvedSymbol].maximumSignificantDigits);
1306b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
1307b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1308b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return result;
13091b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  }
1310b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch);
1311b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1312b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1313b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
1314b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Returns the subset of the given locale list for which this locale list
1315b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * has a matching (possibly fallback) locale. Locales appear in the same
1316b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * order in the returned list as in the input list.
1317b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Options are optional parameter.
1318b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
13191b268ca467c924004286c97bac133db489cf43d0Ben MurdochInstallFunction(Intl.NumberFormat, 'supportedLocalesOf', function(locales) {
1320014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (!IS_UNDEFINED(new.target)) {
1321014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
1322b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
1323b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1324342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    return supportedLocalesOf('numberformat', locales, arguments[1]);
13251b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  }
1326b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch);
1327b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1328b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1329b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
1330b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Returns a String value representing the result of calling ToNumber(value)
1331b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * according to the effective locale and the formatting options of this
1332b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * NumberFormat.
1333b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
1334b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction formatNumber(formatter, value) {
1335b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Spec treats -0 and +0 as 0.
1336014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  var number = TO_NUMBER(value) + 0;
1337b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1338b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return %InternalNumberFormat(%GetImplFromInitializedIntlObject(formatter),
1339b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                               number);
1340b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1341b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1342b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1343b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
1344b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Returns a Number that represents string value that was passed in.
1345b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
1346537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdochfunction IntlParseNumber(formatter, value) {
1347b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return %InternalNumberParse(%GetImplFromInitializedIntlObject(formatter),
134821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch                              TO_STRING(value));
1349b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1350b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1351537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben MurdochAddBoundMethod(Intl.NumberFormat, 'format', formatNumber, 1, 'numberformat');
1352b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1353b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
1354b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Returns a string that matches LDML representation of the options object.
1355b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
1356b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction toLDMLString(options) {
1357b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var getOption = getGetOption(options, 'dateformat');
1358b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1359b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var ldmlString = '';
1360b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1361b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var option = getOption('weekday', 'string', ['narrow', 'short', 'long']);
1362b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  ldmlString += appendToLDMLString(
1363b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      option, {narrow: 'EEEEE', short: 'EEE', long: 'EEEE'});
1364b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1365b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  option = getOption('era', 'string', ['narrow', 'short', 'long']);
1366b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  ldmlString += appendToLDMLString(
1367b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      option, {narrow: 'GGGGG', short: 'GGG', long: 'GGGG'});
1368b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1369b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  option = getOption('year', 'string', ['2-digit', 'numeric']);
1370b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  ldmlString += appendToLDMLString(option, {'2-digit': 'yy', 'numeric': 'y'});
1371b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1372b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  option = getOption('month', 'string',
1373b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                     ['2-digit', 'numeric', 'narrow', 'short', 'long']);
1374b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  ldmlString += appendToLDMLString(option, {'2-digit': 'MM', 'numeric': 'M',
1375b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch          'narrow': 'MMMMM', 'short': 'MMM', 'long': 'MMMM'});
1376b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1377b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  option = getOption('day', 'string', ['2-digit', 'numeric']);
1378b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  ldmlString += appendToLDMLString(
1379b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      option, {'2-digit': 'dd', 'numeric': 'd'});
1380b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1381b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var hr12 = getOption('hour12', 'boolean');
1382b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  option = getOption('hour', 'string', ['2-digit', 'numeric']);
1383014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (IS_UNDEFINED(hr12)) {
1384b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    ldmlString += appendToLDMLString(option, {'2-digit': 'jj', 'numeric': 'j'});
1385b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  } else if (hr12 === true) {
1386b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    ldmlString += appendToLDMLString(option, {'2-digit': 'hh', 'numeric': 'h'});
1387b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  } else {
1388b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    ldmlString += appendToLDMLString(option, {'2-digit': 'HH', 'numeric': 'H'});
1389b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1390b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1391b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  option = getOption('minute', 'string', ['2-digit', 'numeric']);
1392b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  ldmlString += appendToLDMLString(option, {'2-digit': 'mm', 'numeric': 'm'});
1393b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1394b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  option = getOption('second', 'string', ['2-digit', 'numeric']);
1395b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  ldmlString += appendToLDMLString(option, {'2-digit': 'ss', 'numeric': 's'});
1396b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1397b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  option = getOption('timeZoneName', 'string', ['short', 'long']);
1398b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  ldmlString += appendToLDMLString(option, {short: 'z', long: 'zzzz'});
1399b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1400b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return ldmlString;
1401b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1402b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1403b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1404b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
1405b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Returns either LDML equivalent of the current option or empty string.
1406b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
1407b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction appendToLDMLString(option, pairs) {
1408014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (!IS_UNDEFINED(option)) {
1409b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return pairs[option];
1410b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  } else {
1411b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return '';
1412b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1413b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1414b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1415b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1416b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
1417b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Returns object that matches LDML representation of the date.
1418b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
1419b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction fromLDMLString(ldmlString) {
1420b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // First remove '' quoted text, so we lose 'Uhr' strings.
14211b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  ldmlString = InternalRegExpReplace(GetQuotedStringRE(), ldmlString, '');
1422b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1423b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var options = {};
14241b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  var match = InternalRegExpMatch(/E{3,5}/, ldmlString);
1425b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  options = appendToDateTimeObject(
1426b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      options, 'weekday', match, {EEEEE: 'narrow', EEE: 'short', EEEE: 'long'});
1427b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
14281b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  match = InternalRegExpMatch(/G{3,5}/, ldmlString);
1429b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  options = appendToDateTimeObject(
1430b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      options, 'era', match, {GGGGG: 'narrow', GGG: 'short', GGGG: 'long'});
1431b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
14321b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  match = InternalRegExpMatch(/y{1,2}/, ldmlString);
1433b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  options = appendToDateTimeObject(
1434b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      options, 'year', match, {y: 'numeric', yy: '2-digit'});
1435b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
14361b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  match = InternalRegExpMatch(/M{1,5}/, ldmlString);
1437b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  options = appendToDateTimeObject(options, 'month', match, {MM: '2-digit',
1438b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      M: 'numeric', MMMMM: 'narrow', MMM: 'short', MMMM: 'long'});
1439b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1440b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Sometimes we get L instead of M for month - standalone name.
14411b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  match = InternalRegExpMatch(/L{1,5}/, ldmlString);
1442b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  options = appendToDateTimeObject(options, 'month', match, {LL: '2-digit',
1443b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      L: 'numeric', LLLLL: 'narrow', LLL: 'short', LLLL: 'long'});
1444b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
14451b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  match = InternalRegExpMatch(/d{1,2}/, ldmlString);
1446b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  options = appendToDateTimeObject(
1447b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      options, 'day', match, {d: 'numeric', dd: '2-digit'});
1448b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
14491b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  match = InternalRegExpMatch(/h{1,2}/, ldmlString);
1450b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (match !== null) {
1451b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    options['hour12'] = true;
1452b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1453b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  options = appendToDateTimeObject(
1454b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      options, 'hour', match, {h: 'numeric', hh: '2-digit'});
1455b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
14561b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  match = InternalRegExpMatch(/H{1,2}/, ldmlString);
1457b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (match !== null) {
1458b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    options['hour12'] = false;
1459b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1460b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  options = appendToDateTimeObject(
1461b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      options, 'hour', match, {H: 'numeric', HH: '2-digit'});
1462b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
14631b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  match = InternalRegExpMatch(/m{1,2}/, ldmlString);
1464b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  options = appendToDateTimeObject(
1465b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      options, 'minute', match, {m: 'numeric', mm: '2-digit'});
1466b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
14671b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  match = InternalRegExpMatch(/s{1,2}/, ldmlString);
1468b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  options = appendToDateTimeObject(
1469b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      options, 'second', match, {s: 'numeric', ss: '2-digit'});
1470b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
14711b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  match = InternalRegExpMatch(/z|zzzz/, ldmlString);
1472b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  options = appendToDateTimeObject(
1473b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      options, 'timeZoneName', match, {z: 'short', zzzz: 'long'});
1474b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1475b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return options;
1476b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1477b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1478b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1479b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction appendToDateTimeObject(options, option, match, pairs) {
1480b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (IS_NULL(match)) {
14811b268ca467c924004286c97bac133db489cf43d0Ben Murdoch    if (!HAS_OWN_PROPERTY(options, option)) {
1482014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      defineWEProperty(options, option, UNDEFINED);
1483b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
1484b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return options;
1485b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1486b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1487b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var property = match[0];
1488b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  defineWEProperty(options, option, pairs[property]);
1489b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1490b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return options;
1491b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1492b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1493b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1494b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
1495b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Returns options with at least default values in it.
1496b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
1497b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction toDateTimeOptions(options, required, defaults) {
1498014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (IS_UNDEFINED(options)) {
1499b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    options = {};
1500b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  } else {
1501014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    options = TO_OBJECT(options);
1502b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1503b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1504b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var needsDefault = true;
1505b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if ((required === 'date' || required === 'any') &&
1506014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      (!IS_UNDEFINED(options.weekday) || !IS_UNDEFINED(options.year) ||
1507014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch       !IS_UNDEFINED(options.month) || !IS_UNDEFINED(options.day))) {
1508b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    needsDefault = false;
1509b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1510b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1511b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if ((required === 'time' || required === 'any') &&
1512014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      (!IS_UNDEFINED(options.hour) || !IS_UNDEFINED(options.minute) ||
1513014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch       !IS_UNDEFINED(options.second))) {
1514b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    needsDefault = false;
1515b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1516b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1517b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (needsDefault && (defaults === 'date' || defaults === 'all')) {
1518537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch    %object_define_property(options, 'year', {value: 'numeric',
1519537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch                                              writable: true,
1520537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch                                              enumerable: true,
1521537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch                                              configurable: true});
1522537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch    %object_define_property(options, 'month', {value: 'numeric',
1523537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch                                               writable: true,
1524537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch                                               enumerable: true,
1525537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch                                               configurable: true});
1526537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch    %object_define_property(options, 'day', {value: 'numeric',
1527014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                             writable: true,
1528014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                             enumerable: true,
1529014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                             configurable: true});
1530b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1531b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1532537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  if (needsDefault && (defaults === 'time' || defaults === 'all')) {
1533537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch    %object_define_property(options, 'hour', {value: 'numeric',
1534537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch                                              writable: true,
1535537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch                                              enumerable: true,
1536537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch                                              configurable: true});
1537537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch    %object_define_property(options, 'minute', {value: 'numeric',
1538537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch                                                writable: true,
1539537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch                                                enumerable: true,
1540537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch                                                configurable: true});
1541537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch    %object_define_property(options, 'second', {value: 'numeric',
1542537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch                                                writable: true,
1543537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch                                                enumerable: true,
1544537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch                                                configurable: true});
1545537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  }
1546537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch
1547b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return options;
1548b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1549b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1550b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1551b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
1552b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Initializes the given object so it's a valid DateTimeFormat instance.
1553b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Useful for subclassing.
1554b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
1555b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction initializeDateTimeFormat(dateFormat, locales, options) {
1556b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1557b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (%IsInitializedIntlObject(dateFormat)) {
1558014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    throw MakeTypeError(kReinitializeIntl, "DateTimeFormat");
1559b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1560b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1561014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (IS_UNDEFINED(options)) {
1562b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    options = {};
1563b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1564b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1565b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var locale = resolveLocale('dateformat', locales, options);
1566b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1567b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  options = toDateTimeOptions(options, 'any', 'date');
1568b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1569b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var getOption = getGetOption(options, 'dateformat');
1570b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1571b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // We implement only best fit algorithm, but still need to check
1572b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // if the formatMatcher values are in range.
1573b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var matcher = getOption('formatMatcher', 'string',
1574b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                          ['basic', 'best fit'], 'best fit');
1575b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1576b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Build LDML string for the skeleton that we pass to the formatter.
1577b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var ldmlString = toLDMLString(options);
1578b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1579b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Filter out supported extension keys so we know what to put in resolved
1580b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // section later on.
1581b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // We need to pass calendar and number system to the method.
1582b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var tz = canonicalizeTimeZoneID(options.timeZone);
1583b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1584b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // ICU prefers options to be passed using -u- extension key/values, so
1585b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // we need to build that.
1586b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var internalOptions = {};
1587b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var extensionMap = parseExtension(locale.extension);
1588014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1589014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  /**
1590014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch   * Map of Unicode extensions to option properties, and their values and types,
1591014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch   * for a date/time format.
1592014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch   */
1593014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  var DATETIME_FORMAT_KEY_MAP = {
1594014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    'ca': {'property': UNDEFINED, 'type': 'string'},
1595014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    'nu': {'property': UNDEFINED, 'type': 'string'}
1596014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  };
1597014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1598b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var extension = setOptions(options, extensionMap, DATETIME_FORMAT_KEY_MAP,
1599b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                             getOption, internalOptions);
1600b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1601b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var requestedLocale = locale.locale + extension;
1602537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  var resolved = %object_define_properties({}, {
1603b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    calendar: {writable: true},
1604b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    day: {writable: true},
1605b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    era: {writable: true},
1606b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    hour12: {writable: true},
1607b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    hour: {writable: true},
1608b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    locale: {writable: true},
1609b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    minute: {writable: true},
1610b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    month: {writable: true},
1611b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    numberingSystem: {writable: true},
1612014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    [patternSymbol]: {writable: true},
1613b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    requestedLocale: {value: requestedLocale, writable: true},
1614b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    second: {writable: true},
1615b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    timeZone: {writable: true},
1616b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    timeZoneName: {writable: true},
1617b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    tz: {value: tz, writable: true},
1618b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    weekday: {writable: true},
1619b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    year: {writable: true}
1620b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  });
1621b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1622b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var formatter = %CreateDateTimeFormat(
1623b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    requestedLocale, {skeleton: ldmlString, timeZone: tz}, resolved);
1624b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1625014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (resolved.timeZone === "Etc/Unknown") {
1626014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    throw MakeRangeError(kUnsupportedTimeZone, tz);
1627b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1628b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1629b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  %MarkAsInitializedIntlObjectOfType(dateFormat, 'dateformat', formatter);
1630014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  dateFormat[resolvedSymbol] = resolved;
1631537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  if (FLAG_intl_extra) {
1632537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch    %object_define_property(resolved, 'pattern', patternAccessor);
1633537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch    %object_define_property(dateFormat, 'resolved', resolvedAccessor);
1634537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  }
1635b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1636b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return dateFormat;
1637b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1638b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1639b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1640b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
1641b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Constructs Intl.DateTimeFormat object given optional locales and options
1642b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * parameters.
1643b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch *
1644b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * @constructor
1645b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
16461b268ca467c924004286c97bac133db489cf43d0Ben MurdochInstallConstructor(Intl, 'DateTimeFormat', function() {
1647342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    var locales = arguments[0];
1648342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    var options = arguments[1];
1649b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1650b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (!this || this === Intl) {
1651b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      // Constructor is called as a function.
1652b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      return new Intl.DateTimeFormat(locales, options);
1653b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
1654b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1655014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    return initializeDateTimeFormat(TO_OBJECT(this), locales, options);
16561b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  }
1657b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch);
1658b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1659b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1660b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
1661b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * DateTimeFormat resolvedOptions method.
1662b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
16631b268ca467c924004286c97bac133db489cf43d0Ben MurdochInstallFunction(Intl.DateTimeFormat.prototype, 'resolvedOptions', function() {
1664014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (!IS_UNDEFINED(new.target)) {
1665014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
1666b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
1667b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1668b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (!%IsInitializedIntlObjectOfType(this, 'dateformat')) {
1669014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      throw MakeTypeError(kResolvedOptionsCalledOnNonObject, "DateTimeFormat");
1670b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
1671b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1672014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    /**
1673014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch     * Maps ICU calendar names into LDML type.
1674014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch     */
1675014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    var ICU_CALENDAR_MAP = {
1676014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      'gregorian': 'gregory',
1677014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      'japanese': 'japanese',
1678014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      'buddhist': 'buddhist',
1679014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      'roc': 'roc',
1680014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      'persian': 'persian',
1681014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      'islamic-civil': 'islamicc',
1682014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      'islamic': 'islamic',
1683014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      'hebrew': 'hebrew',
1684014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      'chinese': 'chinese',
1685014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      'indian': 'indian',
1686014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      'coptic': 'coptic',
1687014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      'ethiopic': 'ethiopic',
1688014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      'ethiopic-amete-alem': 'ethioaa'
1689014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    };
1690014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1691b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var format = this;
1692014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    var fromPattern = fromLDMLString(format[resolvedSymbol][patternSymbol]);
1693014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    var userCalendar = ICU_CALENDAR_MAP[format[resolvedSymbol].calendar];
1694014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (IS_UNDEFINED(userCalendar)) {
1695b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      // Use ICU name if we don't have a match. It shouldn't happen, but
1696b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      // it would be too strict to throw for this.
1697014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      userCalendar = format[resolvedSymbol].calendar;
1698b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
1699b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1700014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    var locale = getOptimalLanguageTag(format[resolvedSymbol].requestedLocale,
1701014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                       format[resolvedSymbol].locale);
1702b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1703b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var result = {
1704b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      locale: locale,
1705014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      numberingSystem: format[resolvedSymbol].numberingSystem,
1706b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      calendar: userCalendar,
1707014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      timeZone: format[resolvedSymbol].timeZone
1708b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    };
1709b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1710b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    addWECPropertyIfDefined(result, 'timeZoneName', fromPattern.timeZoneName);
1711b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    addWECPropertyIfDefined(result, 'era', fromPattern.era);
1712b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    addWECPropertyIfDefined(result, 'year', fromPattern.year);
1713b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    addWECPropertyIfDefined(result, 'month', fromPattern.month);
1714b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    addWECPropertyIfDefined(result, 'day', fromPattern.day);
1715b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    addWECPropertyIfDefined(result, 'weekday', fromPattern.weekday);
1716b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    addWECPropertyIfDefined(result, 'hour12', fromPattern.hour12);
1717b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    addWECPropertyIfDefined(result, 'hour', fromPattern.hour);
1718b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    addWECPropertyIfDefined(result, 'minute', fromPattern.minute);
1719b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    addWECPropertyIfDefined(result, 'second', fromPattern.second);
1720b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1721b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return result;
17221b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  }
1723b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch);
1724b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1725b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1726b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
1727b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Returns the subset of the given locale list for which this locale list
1728b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * has a matching (possibly fallback) locale. Locales appear in the same
1729b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * order in the returned list as in the input list.
1730b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Options are optional parameter.
1731b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
17321b268ca467c924004286c97bac133db489cf43d0Ben MurdochInstallFunction(Intl.DateTimeFormat, 'supportedLocalesOf', function(locales) {
1733014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (!IS_UNDEFINED(new.target)) {
1734014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
1735b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
1736b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1737342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    return supportedLocalesOf('dateformat', locales, arguments[1]);
17381b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  }
1739b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch);
1740b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1741b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1742b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
1743b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Returns a String value representing the result of calling ToNumber(date)
1744b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * according to the effective locale and the formatting options of this
1745b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * DateTimeFormat.
1746b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
1747b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction formatDate(formatter, dateValue) {
1748b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var dateMs;
1749014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (IS_UNDEFINED(dateValue)) {
1750014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    dateMs = %DateCurrentTime();
1751b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  } else {
1752014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    dateMs = TO_NUMBER(dateValue);
1753b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1754b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
175521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  if (!NUMBER_IS_FINITE(dateMs)) throw MakeRangeError(kDateRange);
1756b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1757b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return %InternalDateFormat(%GetImplFromInitializedIntlObject(formatter),
1758014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                             new GlobalDate(dateMs));
1759b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1760b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1761b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1762b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
1763b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Returns a Date object representing the result of calling ToString(value)
1764b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * according to the effective locale and the formatting options of this
1765b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * DateTimeFormat.
1766b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Returns undefined if date string cannot be parsed.
1767b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
1768537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdochfunction IntlParseDate(formatter, value) {
1769b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return %InternalDateParse(%GetImplFromInitializedIntlObject(formatter),
177021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch                            TO_STRING(value));
1771b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1772b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1773b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1774b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// 0 because date is optional argument.
1775537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben MurdochAddBoundMethod(Intl.DateTimeFormat, 'format', formatDate, 0, 'dateformat');
1776b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1777b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1778b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
1779014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch * Returns canonical Area/Location(/Location) name, or throws an exception
1780014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch * if the zone name is invalid IANA name.
1781b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
1782b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction canonicalizeTimeZoneID(tzID) {
1783b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Skip undefined zones.
1784014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (IS_UNDEFINED(tzID)) {
1785b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return tzID;
1786b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1787b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1788b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Special case handling (UTC, GMT).
1789014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  var upperID = %StringToUpperCase(tzID);
1790b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (upperID === 'UTC' || upperID === 'GMT' ||
1791b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      upperID === 'ETC/UTC' || upperID === 'ETC/GMT') {
1792b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return 'UTC';
1793b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1794b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1795014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // TODO(jshin): Add support for Etc/GMT[+-]([1-9]|1[0-2])
1796014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1797014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // We expect only _, '-' and / beside ASCII letters.
1798014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  // All inputs should conform to Area/Location(/Location)* from now on.
17991b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  var match = InternalRegExpMatch(GetTimezoneNameCheckRE(), tzID);
1800014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (IS_NULL(match)) throw MakeRangeError(kExpectedTimezoneID, tzID);
1801b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1802014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  var result = toTitleCaseTimezoneLocation(match[1]) + '/' +
1803014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch               toTitleCaseTimezoneLocation(match[2]);
1804014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1805014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (!IS_UNDEFINED(match[3]) && 3 < match.length) {
1806014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    var locations = %_Call(StringSplit, match[3], '/');
1807014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    // The 1st element is empty. Starts with i=1.
1808014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    for (var i = 1; i < locations.length; i++) {
1809014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      result = result + '/' + toTitleCaseTimezoneLocation(locations[i]);
1810014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    }
1811b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1812b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1813b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return result;
1814b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1815b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1816b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
1817b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Initializes the given object so it's a valid BreakIterator instance.
1818b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Useful for subclassing.
1819b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
1820b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction initializeBreakIterator(iterator, locales, options) {
1821b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (%IsInitializedIntlObject(iterator)) {
1822014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    throw MakeTypeError(kReinitializeIntl, "v8BreakIterator");
1823b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1824b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1825014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (IS_UNDEFINED(options)) {
1826b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    options = {};
1827b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
1828b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1829b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var getOption = getGetOption(options, 'breakiterator');
1830b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1831b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var internalOptions = {};
1832b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1833b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  defineWEProperty(internalOptions, 'type', getOption(
1834b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    'type', 'string', ['character', 'word', 'sentence', 'line'], 'word'));
1835b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1836b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var locale = resolveLocale('breakiterator', locales, options);
1837537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  var resolved = %object_define_properties({}, {
1838b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    requestedLocale: {value: locale.locale, writable: true},
1839b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    type: {value: internalOptions.type, writable: true},
1840b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    locale: {writable: true}
1841b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  });
1842b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1843b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var internalIterator = %CreateBreakIterator(locale.locale,
1844b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              internalOptions,
1845b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                              resolved);
1846b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1847b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  %MarkAsInitializedIntlObjectOfType(iterator, 'breakiterator',
1848b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                     internalIterator);
1849014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  iterator[resolvedSymbol] = resolved;
1850537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  if (FLAG_intl_extra) {
1851537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch    %object_define_property(iterator, 'resolved', resolvedAccessor);
1852537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  }
1853b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1854b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return iterator;
1855b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1856b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1857b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1858b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
1859b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Constructs Intl.v8BreakIterator object given optional locales and options
1860b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * parameters.
1861b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch *
1862b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * @constructor
1863b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
18641b268ca467c924004286c97bac133db489cf43d0Ben MurdochInstallConstructor(Intl, 'v8BreakIterator', function() {
1865342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    var locales = arguments[0];
1866342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    var options = arguments[1];
1867b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1868b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (!this || this === Intl) {
1869b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      // Constructor is called as a function.
1870b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      return new Intl.v8BreakIterator(locales, options);
1871b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
1872b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1873014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    return initializeBreakIterator(TO_OBJECT(this), locales, options);
18741b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  }
1875b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch);
1876b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1877b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1878b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
1879b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * BreakIterator resolvedOptions method.
1880b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
18811b268ca467c924004286c97bac133db489cf43d0Ben MurdochInstallFunction(Intl.v8BreakIterator.prototype, 'resolvedOptions',
1882b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  function() {
1883014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (!IS_UNDEFINED(new.target)) {
1884014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
1885b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
1886b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1887b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (!%IsInitializedIntlObjectOfType(this, 'breakiterator')) {
1888014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      throw MakeTypeError(kResolvedOptionsCalledOnNonObject, "v8BreakIterator");
1889b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
1890b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1891b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var segmenter = this;
1892014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    var locale =
1893014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        getOptimalLanguageTag(segmenter[resolvedSymbol].requestedLocale,
1894014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                              segmenter[resolvedSymbol].locale);
1895b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1896b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return {
1897b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      locale: locale,
1898014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      type: segmenter[resolvedSymbol].type
1899b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    };
19001b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  }
1901b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch);
1902b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1903b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1904b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
1905b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Returns the subset of the given locale list for which this locale list
1906b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * has a matching (possibly fallback) locale. Locales appear in the same
1907b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * order in the returned list as in the input list.
1908b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Options are optional parameter.
1909b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
19101b268ca467c924004286c97bac133db489cf43d0Ben MurdochInstallFunction(Intl.v8BreakIterator, 'supportedLocalesOf',
1911b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  function(locales) {
1912014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (!IS_UNDEFINED(new.target)) {
1913014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
1914b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
1915b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1916342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    return supportedLocalesOf('breakiterator', locales, arguments[1]);
19171b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  }
1918b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch);
1919b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1920b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1921b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
1922b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Adopts text to segment using the iterator. Old text, if present,
1923b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * gets discarded.
1924b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
1925b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction adoptText(iterator, text) {
1926b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  %BreakIteratorAdoptText(%GetImplFromInitializedIntlObject(iterator),
192721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch                          TO_STRING(text));
1928b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1929b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1930b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1931b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
1932b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Returns index of the first break in the string and moves current pointer.
1933b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
1934b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction first(iterator) {
1935b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return %BreakIteratorFirst(%GetImplFromInitializedIntlObject(iterator));
1936b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1937b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1938b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1939b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
1940b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Returns the index of the next break and moves the pointer.
1941b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
1942b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction next(iterator) {
1943b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return %BreakIteratorNext(%GetImplFromInitializedIntlObject(iterator));
1944b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1945b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1946b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1947b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
1948b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Returns index of the current break.
1949b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
1950b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction current(iterator) {
1951b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return %BreakIteratorCurrent(%GetImplFromInitializedIntlObject(iterator));
1952b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1953b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1954b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1955b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
1956b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Returns type of the current break.
1957b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
1958b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction breakType(iterator) {
1959b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return %BreakIteratorBreakType(%GetImplFromInitializedIntlObject(iterator));
1960b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
1961b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1962b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1963537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben MurdochAddBoundMethod(Intl.v8BreakIterator, 'adoptText', adoptText, 1,
1964537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch               'breakiterator');
1965537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben MurdochAddBoundMethod(Intl.v8BreakIterator, 'first', first, 0, 'breakiterator');
1966537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben MurdochAddBoundMethod(Intl.v8BreakIterator, 'next', next, 0, 'breakiterator');
1967537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben MurdochAddBoundMethod(Intl.v8BreakIterator, 'current', current, 0, 'breakiterator');
1968537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben MurdochAddBoundMethod(Intl.v8BreakIterator, 'breakType', breakType, 0,
1969537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch               'breakiterator');
1970b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1971b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Save references to Intl objects and methods we use, for added security.
1972b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvar savedObjects = {
1973b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  'collator': Intl.Collator,
1974b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  'numberformat': Intl.NumberFormat,
1975b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  'dateformatall': Intl.DateTimeFormat,
1976b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  'dateformatdate': Intl.DateTimeFormat,
1977b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  'dateformattime': Intl.DateTimeFormat
1978b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch};
1979b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1980b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
1981b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Default (created with undefined locales and options parameters) collator,
1982b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// number and date format instances. They'll be created as needed.
1983b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvar defaultObjects = {
1984014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  'collator': UNDEFINED,
1985014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  'numberformat': UNDEFINED,
1986014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  'dateformatall': UNDEFINED,
1987014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  'dateformatdate': UNDEFINED,
1988014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  'dateformattime': UNDEFINED,
1989b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch};
1990b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
199121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdochfunction clearDefaultObjects() {
199221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  defaultObjects['dateformatall'] = UNDEFINED;
199321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  defaultObjects['dateformatdate'] = UNDEFINED;
199421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  defaultObjects['dateformattime'] = UNDEFINED;
199521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch}
199621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch
199721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdochvar date_cache_version = 0;
199821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch
199921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdochfunction checkDateCacheCurrent() {
200021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  var new_date_cache_version = %DateCacheVersion();
200121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  if (new_date_cache_version == date_cache_version) {
200221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch    return;
200321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  }
200421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  date_cache_version = new_date_cache_version;
200521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch
200621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  clearDefaultObjects();
200721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch}
2008b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2009b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
2010b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Returns cached or newly created instance of a given service.
2011b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * We cache only default instances (where no locales or options are provided).
2012b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
2013b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction cachedOrNewService(service, locales, options, defaults) {
2014014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  var useOptions = (IS_UNDEFINED(defaults)) ? options : defaults;
2015014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (IS_UNDEFINED(locales) && IS_UNDEFINED(options)) {
201621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch    checkDateCacheCurrent();
2017014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (IS_UNDEFINED(defaultObjects[service])) {
2018b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      defaultObjects[service] = new savedObjects[service](locales, useOptions);
2019b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
2020b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return defaultObjects[service];
2021b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
2022b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return new savedObjects[service](locales, useOptions);
2023b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
2024b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2025537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdochfunction LocaleConvertCase(s, locales, isToUpper) {
2026537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  // ECMA 402 section 13.1.2 steps 1 through 12.
2027537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  var language;
2028537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  // Optimize for the most common two cases. initializeLocaleList() can handle
2029537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  // them as well, but it's rather slow accounting for over 60% of
2030537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  // toLocale{U,L}Case() and about 40% of toLocale{U,L}Case("<locale>").
2031537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  if (IS_UNDEFINED(locales)) {
2032537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch    language = GetDefaultICULocaleJS();
2033537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  } else if (IS_STRING(locales)) {
2034537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch    language = canonicalizeLanguageTag(locales);
2035537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  } else {
2036537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch    var locales = initializeLocaleList(locales);
2037537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch    language = locales.length > 0 ? locales[0] : GetDefaultICULocaleJS();
2038537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  }
2039537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch
2040537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  // StringSplit is slower than this.
2041537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  var pos = %_Call(StringIndexOf, language, '-');
2042537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  if (pos != -1) {
2043537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch    language = %_Call(StringSubstring, language, 0, pos);
2044537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  }
2045537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch
2046537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  var CUSTOM_CASE_LANGUAGES = ['az', 'el', 'lt', 'tr'];
2047537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  var langIndex = %_Call(ArrayIndexOf, CUSTOM_CASE_LANGUAGES, language);
2048537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  if (langIndex == -1) {
2049537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch    // language-independent case conversion.
2050537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch    return isToUpper ? %StringToUpperCaseI18N(s) : %StringToLowerCaseI18N(s);
2051537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  }
2052537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  return %StringLocaleConvertCase(s, isToUpper,
2053537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch                                  CUSTOM_CASE_LANGUAGES[langIndex]);
2054537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch}
2055537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch
2056b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
2057b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Compares this and that, and returns less than 0, 0 or greater than 0 value.
2058b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Overrides the built-in method.
2059b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
2060014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochOverrideFunction(GlobalString.prototype, 'localeCompare', function(that) {
2061014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (!IS_UNDEFINED(new.target)) {
2062014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
2063b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
2064b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2065b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (IS_NULL_OR_UNDEFINED(this)) {
2066014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      throw MakeTypeError(kMethodInvokedOnNullOrUndefined);
2067b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
2068b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2069342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    var locales = arguments[1];
2070342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    var options = arguments[2];
2071b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var collator = cachedOrNewService('collator', locales, options);
2072b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return compare(collator, this, that);
2073014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2074014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch);
2075b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2076b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2077b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
2078b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Unicode normalization. This method is called with one argument that
2079b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * specifies the normalization form.
2080b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * If none is specified, "NFC" is assumed.
2081b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * If the form is not one of "NFC", "NFD", "NFKC", or "NFKD", then throw
2082b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * a RangeError Exception.
2083b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
2084014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2085014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochOverrideFunction(GlobalString.prototype, 'normalize', function() {
2086014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (!IS_UNDEFINED(new.target)) {
2087014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
2088b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
2089b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2090b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    CHECK_OBJECT_COERCIBLE(this, "String.prototype.normalize");
2091014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    var s = TO_STRING(this);
2092014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
2093342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    var formArg = arguments[0];
2094014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    var form = IS_UNDEFINED(formArg) ? 'NFC' : TO_STRING(formArg);
2095b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2096014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    var NORMALIZATION_FORMS = ['NFC', 'NFD', 'NFKC', 'NFKD'];
2097b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2098014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    var normalizationForm = %_Call(ArrayIndexOf, NORMALIZATION_FORMS, form);
2099b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (normalizationForm === -1) {
2100014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      throw MakeRangeError(kNormalizationForm,
2101014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch          %_Call(ArrayJoin, NORMALIZATION_FORMS, ', '));
2102b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
2103b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2104014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    return %StringNormalize(s, normalizationForm);
2105014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2106014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch);
2107b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2108537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdochfunction ToLowerCaseI18N() {
2109537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  if (!IS_UNDEFINED(new.target)) {
2110537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch    throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
2111537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  }
2112537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  CHECK_OBJECT_COERCIBLE(this, "String.prototype.toLowerCase");
2113537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  var s = TO_STRING(this);
2114537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  return %StringToLowerCaseI18N(s);
2115537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch}
2116537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch
2117537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdochfunction ToUpperCaseI18N() {
2118537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  if (!IS_UNDEFINED(new.target)) {
2119537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch    throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
2120537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  }
2121537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  CHECK_OBJECT_COERCIBLE(this, "String.prototype.toUpperCase");
2122537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  var s = TO_STRING(this);
2123537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  return %StringToUpperCaseI18N(s);
2124537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch}
2125537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch
2126537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdochfunction ToLocaleLowerCaseI18N(locales) {
2127537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  if (!IS_UNDEFINED(new.target)) {
2128537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch    throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
2129537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  }
2130537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  CHECK_OBJECT_COERCIBLE(this, "String.prototype.toLocaleLowerCase");
2131537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  return LocaleConvertCase(TO_STRING(this), locales, false);
2132537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch}
2133537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch
2134537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch%FunctionSetLength(ToLocaleLowerCaseI18N, 0);
2135537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch
2136537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdochfunction ToLocaleUpperCaseI18N(locales) {
2137537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  if (!IS_UNDEFINED(new.target)) {
2138537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch    throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
2139537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  }
2140537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  CHECK_OBJECT_COERCIBLE(this, "String.prototype.toLocaleUpperCase");
2141537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  return LocaleConvertCase(TO_STRING(this), locales, true);
2142537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch}
2143537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch
2144537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch%FunctionSetLength(ToLocaleUpperCaseI18N, 0);
2145537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch
2146537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch%FunctionRemovePrototype(ToLowerCaseI18N);
2147537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch%FunctionRemovePrototype(ToUpperCaseI18N);
2148537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch%FunctionRemovePrototype(ToLocaleLowerCaseI18N);
2149537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch%FunctionRemovePrototype(ToLocaleUpperCaseI18N);
2150537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch
2151537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdochutils.Export(function(to) {
2152537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  to.ToLowerCaseI18N = ToLowerCaseI18N;
2153537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  to.ToUpperCaseI18N = ToUpperCaseI18N;
2154537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  to.ToLocaleLowerCaseI18N = ToLocaleLowerCaseI18N;
2155537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  to.ToLocaleUpperCaseI18N = ToLocaleUpperCaseI18N;
2156537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch});
2157537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch
2158b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2159b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
2160b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Formats a Number object (this) using locale and options values.
2161b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * If locale or options are omitted, defaults are used.
2162b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
2163014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochOverrideFunction(GlobalNumber.prototype, 'toLocaleString', function() {
2164014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (!IS_UNDEFINED(new.target)) {
2165014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
2166b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
2167b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2168014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (!(this instanceof GlobalNumber) && typeof(this) !== 'number') {
2169014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      throw MakeTypeError(kMethodInvokedOnWrongType, "Number");
2170b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
2171b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2172342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    var locales = arguments[0];
2173342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    var options = arguments[1];
2174b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var numberFormat = cachedOrNewService('numberformat', locales, options);
2175b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return formatNumber(numberFormat, this);
2176014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2177014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch);
2178b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2179b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2180b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
2181b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Returns actual formatted date or fails if date parameter is invalid.
2182b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
2183b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction toLocaleDateTime(date, locales, options, required, defaults, service) {
2184014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (!(date instanceof GlobalDate)) {
2185014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    throw MakeTypeError(kMethodInvokedOnWrongType, "Date");
2186b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
2187b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2188014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (IsNaN(date)) return 'Invalid Date';
2189b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2190b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var internalOptions = toDateTimeOptions(options, required, defaults);
2191b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2192b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var dateFormat =
2193b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      cachedOrNewService(service, locales, options, internalOptions);
2194b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2195b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return formatDate(dateFormat, date);
2196b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
2197b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2198b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2199b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
2200b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Formats a Date object (this) using locale and options values.
2201b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * If locale or options are omitted, defaults are used - both date and time are
2202b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * present in the output.
2203b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
2204014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochOverrideFunction(GlobalDate.prototype, 'toLocaleString', function() {
2205014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (!IS_UNDEFINED(new.target)) {
2206014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
2207b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
2208b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2209342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    var locales = arguments[0];
2210342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    var options = arguments[1];
2211b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return toLocaleDateTime(
2212b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        this, locales, options, 'any', 'all', 'dateformatall');
2213014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2214014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch);
2215b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2216b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2217b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
2218b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Formats a Date object (this) using locale and options values.
2219b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * If locale or options are omitted, defaults are used - only date is present
2220b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * in the output.
2221b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
2222014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochOverrideFunction(GlobalDate.prototype, 'toLocaleDateString', function() {
2223014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (!IS_UNDEFINED(new.target)) {
2224014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
2225b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
2226b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2227342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    var locales = arguments[0];
2228342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    var options = arguments[1];
2229b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return toLocaleDateTime(
2230b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        this, locales, options, 'date', 'date', 'dateformatdate');
2231014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2232014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch);
2233b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2234b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2235b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
2236b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Formats a Date object (this) using locale and options values.
2237b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * If locale or options are omitted, defaults are used - only time is present
2238b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * in the output.
2239b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
2240014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochOverrideFunction(GlobalDate.prototype, 'toLocaleTimeString', function() {
2241014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if (!IS_UNDEFINED(new.target)) {
2242014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
2243b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
2244b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2245342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    var locales = arguments[0];
2246342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    var options = arguments[1];
2247b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    return toLocaleDateTime(
2248b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        this, locales, options, 'time', 'time', 'dateformattime');
2249014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  }
2250014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch);
2251b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
2252537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdochutils.Export(function(to) {
2253537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  to.AddBoundMethod = AddBoundMethod;
2254537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  to.IntlParseDate = IntlParseDate;
2255537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch  to.IntlParseNumber = IntlParseNumber;
2256537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch});
2257537ba893e2530051ec7f296e769fdd37bb4ae4a0Ben Murdoch
2258014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch})
2259