diff options
Diffstat (limited to 'deps/v8/src/js/i18n.js')
-rw-r--r-- | deps/v8/src/js/i18n.js | 579 |
1 files changed, 369 insertions, 210 deletions
diff --git a/deps/v8/src/js/i18n.js b/deps/v8/src/js/i18n.js index 845289a91f..6046a6f2f9 100644 --- a/deps/v8/src/js/i18n.js +++ b/deps/v8/src/js/i18n.js @@ -17,26 +17,19 @@ // ------------------------------------------------------------------- // Imports -var ArrayIndexOf; var ArrayJoin; var ArrayPush; -var GlobalBoolean = global.Boolean; +var FLAG_intl_extra; var GlobalDate = global.Date; var GlobalNumber = global.Number; var GlobalRegExp = global.RegExp; var GlobalString = global.String; var InstallFunctions = utils.InstallFunctions; var InstallGetter = utils.InstallGetter; -var InternalPackedArray = utils.InternalPackedArray; +var InternalArray = utils.InternalArray; var InternalRegExpMatch; var InternalRegExpReplace -var IsFinite; var IsNaN; -var MakeError; -var MakeRangeError; -var MakeTypeError; -var ObjectDefineProperties = utils.ImportNow("ObjectDefineProperties"); -var ObjectDefineProperty = utils.ImportNow("ObjectDefineProperty"); var ObjectHasOwnProperty = utils.ImportNow("ObjectHasOwnProperty"); var OverrideFunction = utils.OverrideFunction; var patternSymbol = utils.ImportNow("intl_pattern_symbol"); @@ -44,28 +37,25 @@ var resolvedSymbol = utils.ImportNow("intl_resolved_symbol"); var SetFunctionName = utils.SetFunctionName; var StringIndexOf; var StringLastIndexOf; -var StringSplit; var StringSubstr; var StringSubstring; utils.Import(function(from) { - ArrayIndexOf = from.ArrayIndexOf; ArrayJoin = from.ArrayJoin; ArrayPush = from.ArrayPush; - IsFinite = from.IsFinite; IsNaN = from.IsNaN; - MakeError = from.MakeError; - MakeRangeError = from.MakeRangeError; - MakeTypeError = from.MakeTypeError; InternalRegExpMatch = from.InternalRegExpMatch; InternalRegExpReplace = from.InternalRegExpReplace; StringIndexOf = from.StringIndexOf; StringLastIndexOf = from.StringLastIndexOf; - StringSplit = from.StringSplit; StringSubstr = from.StringSubstr; StringSubstring = from.StringSubstring; }); +utils.ImportFromExperimental(function(from) { + FLAG_intl_extra = from.FLAG_intl_extra; +}); + // Utilities for definitions function InstallFunction(object, name, func) { @@ -84,43 +74,45 @@ function InstallConstructor(object, name, func) { /** * Adds bound method to the prototype of the given object. */ -function AddBoundMethod(obj, methodName, implementation, length) { +function AddBoundMethod(obj, methodName, implementation, length, type) { %CheckIsBootstrapping(); var internalName = %CreatePrivateSymbol(methodName); - var getter = function() { - if (!%IsInitializedIntlObject(this)) { - throw MakeTypeError(kMethodCalledOnWrongObject, methodName); + // Making getter an anonymous function will cause + // %DefineGetterPropertyUnchecked to properly set the "name" + // property on each JSFunction instance created here, rather + // than (as utils.InstallGetter would) on the SharedFunctionInfo + // associated with all functions returned from AddBoundMethod. + var getter = ANONYMOUS_FUNCTION(function() { + if (!%IsInitializedIntlObjectOfType(this, type)) { + throw %make_type_error(kMethodCalledOnWrongObject, methodName); } if (IS_UNDEFINED(this[internalName])) { var boundMethod; if (IS_UNDEFINED(length) || length === 2) { - boundMethod = (x, y) => implementation(this, x, y); + boundMethod = ANONYMOUS_FUNCTION((x, y) => implementation(this, x, y)); } else if (length === 1) { - boundMethod = x => implementation(this, x); + boundMethod = ANONYMOUS_FUNCTION(x => implementation(this, x)); } else { - boundMethod = (...args) => { - // DateTimeFormat.format needs to be 0 arg method, but can stil - // receive optional dateValue param. If one was provided, pass it + boundMethod = ANONYMOUS_FUNCTION((...args) => { + // DateTimeFormat.format needs to be 0 arg method, but can still + // receive an optional dateValue param. If one was provided, pass it // along. if (args.length > 0) { return implementation(this, args[0]); } else { return implementation(this); } - } + }); } - // TODO(littledan): Once function name reform is shipped, remove the - // following line and wrap the boundMethod definition in an anonymous - // function macro. - %FunctionSetName(boundMethod, '__bound' + methodName + '__'); - %FunctionRemovePrototype(boundMethod); %SetNativeFlag(boundMethod); this[internalName] = boundMethod; } return this[internalName]; - }; + }); - InstallGetter(obj.prototype, methodName, getter, DONT_ENUM); + %FunctionRemovePrototype(getter); + %DefineGetterPropertyUnchecked(obj.prototype, methodName, getter, DONT_ENUM); + %SetNativeFlag(getter); } // ------------------------------------------------------------------- @@ -144,6 +136,13 @@ var AVAILABLE_LOCALES = { */ var DEFAULT_ICU_LOCALE = UNDEFINED; +function GetDefaultICULocaleJS() { + if (IS_UNDEFINED(DEFAULT_ICU_LOCALE)) { + DEFAULT_ICU_LOCALE = %GetDefaultICULocale(); + } + return DEFAULT_ICU_LOCALE; +} + /** * Unicode extension regular expression. */ @@ -263,7 +262,7 @@ function GetTimezoneNameLocationPartRE() { */ function supportedLocalesOf(service, locales, options) { if (IS_NULL(InternalRegExpMatch(GetServiceRE(), service))) { - throw MakeError(kWrongServiceType, service); + throw %make_error(kWrongServiceType, service); } // Provide defaults if matcher was not specified. @@ -275,9 +274,9 @@ function supportedLocalesOf(service, locales, options) { var matcher = options.localeMatcher; if (!IS_UNDEFINED(matcher)) { - matcher = GlobalString(matcher); + matcher = TO_STRING(matcher); if (matcher !== 'lookup' && matcher !== 'best fit') { - throw MakeRangeError(kLocaleMatcher, matcher); + throw %make_range_error(kLocaleMatcher, matcher); } } else { matcher = 'best fit'; @@ -307,7 +306,7 @@ function supportedLocalesOf(service, locales, options) { * Locales appear in the same order in the returned list as in the input list. */ function lookupSupportedLocalesOf(requestedLocales, availableLocales) { - var matchedLocales = []; + var matchedLocales = new InternalArray(); for (var i = 0; i < requestedLocales.length; ++i) { // Remove -u- extension. var locale = InternalRegExpReplace( @@ -349,27 +348,27 @@ function bestFitSupportedLocalesOf(requestedLocales, availableLocales) { * is out of range for that property it throws RangeError. */ function getGetOption(options, caller) { - if (IS_UNDEFINED(options)) throw MakeError(kDefaultOptionsMissing, caller); + if (IS_UNDEFINED(options)) throw %make_error(kDefaultOptionsMissing, caller); var getOption = function getOption(property, type, values, defaultValue) { if (!IS_UNDEFINED(options[property])) { var value = options[property]; switch (type) { case 'boolean': - value = GlobalBoolean(value); + value = TO_BOOLEAN(value); break; case 'string': - value = GlobalString(value); + value = TO_STRING(value); break; case 'number': - value = GlobalNumber(value); + value = TO_NUMBER(value); break; default: - throw MakeError(kWrongValueType); + throw %make_error(kWrongValueType); } - if (!IS_UNDEFINED(values) && %_Call(ArrayIndexOf, values, value) === -1) { - throw MakeRangeError(kValueOutOfRange, value, caller, property); + if (!IS_UNDEFINED(values) && %ArrayIndexOf(values, value, 0) === -1) { + throw %make_range_error(kValueOutOfRange, value, caller, property); } return value; @@ -383,6 +382,9 @@ function getGetOption(options, caller) { /** + * Ecma 402 9.2.5 + * TODO(jshin): relevantExtensionKeys and localeData need to be taken into + * account per spec. * Compares a BCP 47 language priority list requestedLocales against the locales * in availableLocales and determines the best available language to meet the * request. Two algorithms are available to match the locales: the Lookup @@ -418,7 +420,7 @@ function resolveLocale(service, requestedLocales, options) { */ function lookupMatcher(service, requestedLocales) { if (IS_NULL(InternalRegExpMatch(GetServiceRE(), service))) { - throw MakeError(kWrongServiceType, service); + throw %make_error(kWrongServiceType, service); } // Cache these, they don't ever change per service. @@ -448,11 +450,7 @@ function lookupMatcher(service, requestedLocales) { } // Didn't find a match, return default. - if (IS_UNDEFINED(DEFAULT_ICU_LOCALE)) { - DEFAULT_ICU_LOCALE = %GetDefaultICULocale(); - } - - return {'locale': DEFAULT_ICU_LOCALE, 'extension': '', 'position': -1}; + return {'locale': GetDefaultICULocaleJS(), 'extension': '', 'position': -1}; } @@ -470,9 +468,14 @@ function bestFitMatcher(service, requestedLocales) { * Parses Unicode extension into key - value map. * Returns empty object if the extension string is invalid. * We are not concerned with the validity of the values at this point. + * 'attribute' in RFC 6047 is not supported. Keys without explicit + * values are assigned UNDEFINED. + * TODO(jshin): Fix the handling of 'attribute' (in RFC 6047, but none + * has been defined so that it's not used) and boolean keys without + * an explicit value. */ function parseExtension(extension) { - var extensionSplit = %_Call(StringSplit, extension, '-'); + var extensionSplit = %StringSplit(extension, '-', kMaxUint32); // Assume ['', 'u', ...] input, but don't throw. if (extensionSplit.length <= 2 || @@ -483,21 +486,33 @@ function parseExtension(extension) { // Key is {2}alphanum, value is {3,8}alphanum. // Some keys may not have explicit values (booleans). var extensionMap = {}; - var previousKey = UNDEFINED; + var key = UNDEFINED; + var value = UNDEFINED; for (var i = 2; i < extensionSplit.length; ++i) { var length = extensionSplit[i].length; var element = extensionSplit[i]; if (length === 2) { - extensionMap[element] = UNDEFINED; - previousKey = element; - } else if (length >= 3 && length <=8 && !IS_UNDEFINED(previousKey)) { - extensionMap[previousKey] = element; - previousKey = UNDEFINED; + if (!IS_UNDEFINED(key)) { + if (!(key in extensionMap)) { + extensionMap[key] = value; + } + value = UNDEFINED; + } + key = element; + } else if (length >= 3 && length <= 8 && !IS_UNDEFINED(key)) { + if (IS_UNDEFINED(value)) { + value = element; + } else { + value = value + "-" + element; + } } else { // There is a value that's too long, or that doesn't have a key. return {}; } } + if (!IS_UNDEFINED(key) && !(key in extensionMap)) { + extensionMap[key] = value; + } return extensionMap; } @@ -517,7 +532,7 @@ function setOptions(inOptions, extensionMap, keyValues, getOption, outOptions) { var extension = ''; var updateExtension = function updateExtension(key, value) { - return '-' + key + '-' + GlobalString(value); + return '-' + key + '-' + TO_STRING(value); } var updateProperty = function updateProperty(property, type, value) { @@ -567,24 +582,33 @@ function setOptions(inOptions, extensionMap, keyValues, getOption, outOptions) { /** - * Converts all OwnProperties into + * Given an array-like, outputs an Array with the numbered + * properties copied over and defined * configurable: false, writable: false, enumerable: true. + * When |expandable| is true, the result array can be expanded. */ -function freezeArray(array) { - var l = array.length; +function freezeArray(input) { + var array = []; + var l = input.length; for (var i = 0; i < l; i++) { - if (i in array) { - ObjectDefineProperty(array, i, {value: array[i], - configurable: false, - writable: false, - enumerable: true}); + if (i in input) { + %object_define_property(array, i, {value: input[i], + configurable: false, + writable: false, + enumerable: true}); } } - ObjectDefineProperty(array, 'length', {value: l, writable: false}); + %object_define_property(array, 'length', {value: l, writable: false}); return array; } +/* Make JS array[] out of InternalArray */ +function makeArray(input) { + var array = []; + %MoveArrayContents(input, array); + return array; +} /** * It's sometimes desireable to leave user requested locale instead of ICU @@ -643,8 +667,8 @@ function getAvailableLocalesOf(service) { * Configurable is false by default. */ function defineWEProperty(object, property, value) { - ObjectDefineProperty(object, property, - {value: value, writable: true, enumerable: true}); + %object_define_property(object, property, + {value: value, writable: true, enumerable: true}); } @@ -663,10 +687,10 @@ function addWEPropertyIfDefined(object, property, value) { * Defines a property and sets writable, enumerable and configurable to true. */ function defineWECProperty(object, property, value) { - ObjectDefineProperty(object, property, {value: value, - writable: true, - enumerable: true, - configurable: true}); + %object_define_property(object, property, {value: value, + writable: true, + enumerable: true, + configurable: true}); } @@ -697,14 +721,14 @@ function toTitleCaseWord(word) { */ function toTitleCaseTimezoneLocation(location) { var match = InternalRegExpMatch(GetTimezoneNameLocationPartRE(), location) - if (IS_NULL(match)) throw MakeRangeError(kExpectedLocation, location); + if (IS_NULL(match)) throw %make_range_error(kExpectedLocation, location); var result = toTitleCaseWord(match[1]); if (!IS_UNDEFINED(match[2]) && 2 < match.length) { // The first character is a separator, '_' or '-'. // None of IANA zone names has both '_' and '-'. var separator = %_Call(StringSubstring, match[2], 0, 1); - var parts = %_Call(StringSplit, match[2], separator); + var parts = %StringSplit(match[2], separator, kMaxUint32); for (var i = 1; i < parts.length; i++) { var part = parts[i] var lowercasedPart = %StringToLowerCase(part); @@ -719,27 +743,34 @@ function toTitleCaseTimezoneLocation(location) { /** * Canonicalizes the language tag, or throws in case the tag is invalid. + * ECMA 402 9.2.1 steps 7.c ii ~ v. */ function canonicalizeLanguageTag(localeID) { // null is typeof 'object' so we have to do extra check. - if (typeof localeID !== 'string' && typeof localeID !== 'object' || + if ((!IS_STRING(localeID) && !IS_RECEIVER(localeID)) || IS_NULL(localeID)) { - throw MakeTypeError(kLanguageID); + throw %make_type_error(kLanguageID); + } + + // Optimize for the most common case; a language code alone in + // the canonical form/lowercase (e.g. "en", "fil"). + if (IS_STRING(localeID) && + !IS_NULL(InternalRegExpMatch(/^[a-z]{2,3}$/, localeID))) { + return localeID; } - var localeString = GlobalString(localeID); + var localeString = TO_STRING(localeID); - if (isValidLanguageTag(localeString) === false) { - throw MakeRangeError(kInvalidLanguageTag, localeString); + if (isStructuallyValidLanguageTag(localeString) === false) { + throw %make_range_error(kInvalidLanguageTag, localeString); } - // This call will strip -kn but not -kn-true extensions. - // ICU bug filled - http://bugs.icu-project.org/trac/ticket/9265. - // TODO(cira): check if -u-kn-true-kc-true-kh-true still throws after - // upgrade to ICU 4.9. + // ECMA 402 6.2.3 var tag = %CanonicalizeLanguageTag(localeString); + // TODO(jshin): This should not happen because the structual validity + // is already checked. If that's the case, remove this. if (tag === 'invalid-tag') { - throw MakeRangeError(kInvalidLanguageTag, localeString); + throw %make_range_error(kInvalidLanguageTag, localeString); } return tag; @@ -747,23 +778,22 @@ function canonicalizeLanguageTag(localeID) { /** - * Returns an array where all locales are canonicalized and duplicates removed. + * Returns an InternalArray where all locales are canonicalized and duplicates + * removed. * Throws on locales that are not well formed BCP47 tags. + * ECMA 402 8.2.1 steps 1 (ECMA 402 9.2.1) and 2. */ -function initializeLocaleList(locales) { - var seen = []; - if (IS_UNDEFINED(locales)) { - // Constructor is called without arguments. - seen = []; - } else { +function canonicalizeLocaleList(locales) { + var seen = new InternalArray(); + if (!IS_UNDEFINED(locales)) { // We allow single string localeID. if (typeof locales === 'string') { %_Call(ArrayPush, seen, canonicalizeLanguageTag(locales)); - return freezeArray(seen); + return seen; } var o = TO_OBJECT(locales); - var len = TO_UINT32(o.length); + var len = TO_LENGTH(o.length); for (var k = 0; k < len; k++) { if (k in o) { @@ -771,27 +801,37 @@ function initializeLocaleList(locales) { var tag = canonicalizeLanguageTag(value); - if (%_Call(ArrayIndexOf, seen, tag) === -1) { + if (%ArrayIndexOf(seen, tag, 0) === -1) { %_Call(ArrayPush, seen, tag); } } } } - return freezeArray(seen); + return seen; } +function initializeLocaleList(locales) { + return freezeArray(canonicalizeLocaleList(locales)); +} /** - * Validates the language tag. Section 2.2.9 of the bcp47 spec - * defines a valid tag. + * Check the structual Validity of the language tag per ECMA 402 6.2.2: + * - Well-formed per RFC 5646 2.1 + * - There are no duplicate variant subtags + * - There are no duplicate singletion (extension) subtags + * + * One extra-check is done (from RFC 5646 2.2.9): the tag is compared + * against the list of grandfathered tags. However, subtags for + * primary/extended language, script, region, variant are not checked + * against the IANA language subtag registry. * * ICU is too permissible and lets invalid tags, like * hant-cmn-cn, through. * * Returns false if the language tag is invalid. */ -function isValidLanguageTag(locale) { +function isStructuallyValidLanguageTag(locale) { // Check if it's well-formed, including grandfadered tags. if (IS_NULL(InternalRegExpMatch(GetLanguageTagRE(), locale))) { return false; @@ -805,19 +845,19 @@ function isValidLanguageTag(locale) { // Check if there are any duplicate variants or singletons (extensions). // Remove private use section. - locale = %_Call(StringSplit, locale, '-x-')[0]; + locale = %StringSplit(locale, '-x-', kMaxUint32)[0]; // Skip language since it can match variant regex, so we start from 1. // We are matching i-klingon here, but that's ok, since i-klingon-klingon // is not valid and would fail LANGUAGE_TAG_RE test. - var variants = []; - var extensions = []; - var parts = %_Call(StringSplit, locale, '-'); + var variants = new InternalArray(); + var extensions = new InternalArray(); + var parts = %StringSplit(locale, '-', kMaxUint32); for (var i = 1; i < parts.length; i++) { var value = parts[i]; if (!IS_NULL(InternalRegExpMatch(GetLanguageVariantRE(), value)) && extensions.length === 0) { - if (%_Call(ArrayIndexOf, variants, value) === -1) { + if (%ArrayIndexOf(variants, value, 0) === -1) { %_Call(ArrayPush, variants, value); } else { return false; @@ -825,7 +865,7 @@ function isValidLanguageTag(locale) { } if (!IS_NULL(InternalRegExpMatch(GetLanguageSingletonRE(), value))) { - if (%_Call(ArrayIndexOf, extensions, value) === -1) { + if (%ArrayIndexOf(extensions, value, 0) === -1) { %_Call(ArrayPush, extensions, value); } else { return false; @@ -886,13 +926,23 @@ var resolvedAccessor = { } }; +// ECMA 402 section 8.2.1 +InstallFunction(Intl, 'getCanonicalLocales', function(locales) { + if (!IS_UNDEFINED(new.target)) { + throw %make_type_error(kOrdinaryFunctionCalledAsConstructor); + } + + return makeArray(canonicalizeLocaleList(locales)); + } +); + /** * Initializes the given object so it's a valid Collator instance. * Useful for subclassing. */ function initializeCollator(collator, locales, options) { if (%IsInitializedIntlObject(collator)) { - throw MakeTypeError(kReinitializeIntl, "Collator"); + throw %make_type_error(kReinitializeIntl, "Collator"); } if (IS_UNDEFINED(options)) { @@ -918,6 +968,9 @@ function initializeCollator(collator, locales, options) { var locale = resolveLocale('collator', locales, options); + // TODO(jshin): ICU now can take kb, kc, etc. Switch over to using ICU + // directly. See Collator::InitializeCollator and + // Collator::CreateICUCollator in src/i18n.cc // ICU can't take kb, kc... parameters through localeID, so we need to pass // them as options. // One exception is -co- which has to be part of the extension, but only for @@ -950,7 +1003,7 @@ function initializeCollator(collator, locales, options) { 'pinyin', 'reformed', 'searchjl', 'stroke', 'trad', 'unihan', 'zhuyin' ]; - if (%_Call(ArrayIndexOf, ALLOWED_CO_VALUES, extensionMap.co) !== -1) { + if (%ArrayIndexOf(ALLOWED_CO_VALUES, extensionMap.co, 0) !== -1) { extension = '-u-co-' + extensionMap.co; // ICU can't tell us what the collation is, so save user's input. collation = extensionMap.co; @@ -965,8 +1018,8 @@ function initializeCollator(collator, locales, options) { // We define all properties C++ code may produce, to prevent security // problems. If malicious user decides to redefine Object.prototype.locale // we can't just use plain x.locale = 'us' or in C++ Set("locale", "us"). - // ObjectDefineProperties will either succeed defining or throw an error. - var resolved = ObjectDefineProperties({}, { + // %object_define_properties will either succeed defining or throw an error. + var resolved = %object_define_properties({}, { caseFirst: {writable: true}, collation: {value: internalOptions.collation, writable: true}, ignorePunctuation: {writable: true}, @@ -985,7 +1038,9 @@ function initializeCollator(collator, locales, options) { // Writable, configurable and enumerable are set to false by default. %MarkAsInitializedIntlObjectOfType(collator, 'collator', internalCollator); collator[resolvedSymbol] = resolved; - ObjectDefineProperty(collator, 'resolved', resolvedAccessor); + if (FLAG_intl_extra) { + %object_define_property(collator, 'resolved', resolvedAccessor); + } return collator; } @@ -1016,11 +1071,11 @@ InstallConstructor(Intl, 'Collator', function() { */ InstallFunction(Intl.Collator.prototype, 'resolvedOptions', function() { if (!IS_UNDEFINED(new.target)) { - throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor); + throw %make_type_error(kOrdinaryFunctionCalledAsConstructor); } if (!%IsInitializedIntlObjectOfType(this, 'collator')) { - throw MakeTypeError(kResolvedOptionsCalledOnNonObject, "Collator"); + throw %make_type_error(kResolvedOptionsCalledOnNonObject, "Collator"); } var coll = this; @@ -1048,7 +1103,7 @@ InstallFunction(Intl.Collator.prototype, 'resolvedOptions', function() { */ InstallFunction(Intl.Collator, 'supportedLocalesOf', function(locales) { if (!IS_UNDEFINED(new.target)) { - throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor); + throw %make_type_error(kOrdinaryFunctionCalledAsConstructor); } return supportedLocalesOf('collator', locales, arguments[1]); @@ -1068,11 +1123,11 @@ InstallFunction(Intl.Collator, 'supportedLocalesOf', function(locales) { */ function compare(collator, x, y) { return %InternalCompare(%GetImplFromInitializedIntlObject(collator), - GlobalString(x), GlobalString(y)); + TO_STRING(x), TO_STRING(y)); }; -AddBoundMethod(Intl.Collator, 'compare', compare, 2); +AddBoundMethod(Intl.Collator, 'compare', compare, 2, 'collator'); /** * Verifies that the input is a well-formed ISO 4217 currency code. @@ -1092,9 +1147,9 @@ function isWellFormedCurrencyCode(currency) { function getNumberOption(options, property, min, max, fallback) { var value = options[property]; if (!IS_UNDEFINED(value)) { - value = GlobalNumber(value); - if (IsNaN(value) || value < min || value > max) { - throw MakeRangeError(kPropertyValueOutOfRange, property); + value = TO_NUMBER(value); + if (NUMBER_IS_NAN(value) || value < min || value > max) { + throw %make_range_error(kPropertyValueOutOfRange, property); } return %math_floor(value); } @@ -1118,7 +1173,7 @@ var patternAccessor = { */ function initializeNumberFormat(numberFormat, locales, options) { if (%IsInitializedIntlObject(numberFormat)) { - throw MakeTypeError(kReinitializeIntl, "NumberFormat"); + throw %make_type_error(kReinitializeIntl, "NumberFormat"); } if (IS_UNDEFINED(options)) { @@ -1135,11 +1190,11 @@ function initializeNumberFormat(numberFormat, locales, options) { var currency = getOption('currency', 'string'); if (!IS_UNDEFINED(currency) && !isWellFormedCurrencyCode(currency)) { - throw MakeRangeError(kInvalidCurrencyCode, currency); + throw %make_range_error(kInvalidCurrencyCode, currency); } if (internalOptions.style === 'currency' && IS_UNDEFINED(currency)) { - throw MakeTypeError(kCurrencyCode); + throw %make_type_error(kCurrencyCode); } var currencyDisplay = getOption( @@ -1198,7 +1253,7 @@ function initializeNumberFormat(numberFormat, locales, options) { getOption, internalOptions); var requestedLocale = locale.locale + extension; - var resolved = ObjectDefineProperties({}, { + var resolved = %object_define_properties({}, { currency: {writable: true}, currencyDisplay: {writable: true}, locale: {writable: true}, @@ -1206,7 +1261,6 @@ function initializeNumberFormat(numberFormat, locales, options) { minimumFractionDigits: {writable: true}, minimumIntegerDigits: {writable: true}, numberingSystem: {writable: true}, - pattern: patternAccessor, requestedLocale: {value: requestedLocale, writable: true}, style: {value: internalOptions.style, writable: true}, useGrouping: {writable: true} @@ -1222,13 +1276,16 @@ function initializeNumberFormat(numberFormat, locales, options) { resolved); if (internalOptions.style === 'currency') { - ObjectDefineProperty(resolved, 'currencyDisplay', {value: currencyDisplay, - writable: true}); + %object_define_property(resolved, 'currencyDisplay', + {value: currencyDisplay, writable: true}); } %MarkAsInitializedIntlObjectOfType(numberFormat, 'numberformat', formatter); numberFormat[resolvedSymbol] = resolved; - ObjectDefineProperty(numberFormat, 'resolved', resolvedAccessor); + if (FLAG_intl_extra) { + %object_define_property(resolved, 'pattern', patternAccessor); + %object_define_property(numberFormat, 'resolved', resolvedAccessor); + } return numberFormat; } @@ -1259,11 +1316,11 @@ InstallConstructor(Intl, 'NumberFormat', function() { */ InstallFunction(Intl.NumberFormat.prototype, 'resolvedOptions', function() { if (!IS_UNDEFINED(new.target)) { - throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor); + throw %make_type_error(kOrdinaryFunctionCalledAsConstructor); } if (!%IsInitializedIntlObjectOfType(this, 'numberformat')) { - throw MakeTypeError(kResolvedOptionsCalledOnNonObject, "NumberFormat"); + throw %make_type_error(kResolvedOptionsCalledOnNonObject, "NumberFormat"); } var format = this; @@ -1309,7 +1366,7 @@ InstallFunction(Intl.NumberFormat.prototype, 'resolvedOptions', function() { */ InstallFunction(Intl.NumberFormat, 'supportedLocalesOf', function(locales) { if (!IS_UNDEFINED(new.target)) { - throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor); + throw %make_type_error(kOrdinaryFunctionCalledAsConstructor); } return supportedLocalesOf('numberformat', locales, arguments[1]); @@ -1334,14 +1391,12 @@ function formatNumber(formatter, value) { /** * Returns a Number that represents string value that was passed in. */ -function parseNumber(formatter, value) { +function IntlParseNumber(formatter, value) { return %InternalNumberParse(%GetImplFromInitializedIntlObject(formatter), - GlobalString(value)); + TO_STRING(value)); } - -AddBoundMethod(Intl.NumberFormat, 'format', formatNumber, 1); -AddBoundMethod(Intl.NumberFormat, 'v8Parse', parseNumber, 1); +AddBoundMethod(Intl.NumberFormat, 'format', formatNumber, 1, 'numberformat'); /** * Returns a string that matches LDML representation of the options object. @@ -1508,35 +1563,35 @@ function toDateTimeOptions(options, required, defaults) { } if (needsDefault && (defaults === 'date' || defaults === 'all')) { - ObjectDefineProperty(options, 'year', {value: 'numeric', - writable: true, - enumerable: true, - configurable: true}); - ObjectDefineProperty(options, 'month', {value: 'numeric', - writable: true, - enumerable: true, - configurable: true}); - ObjectDefineProperty(options, 'day', {value: 'numeric', - writable: true, - enumerable: true, - configurable: true}); - } - - if (needsDefault && (defaults === 'time' || defaults === 'all')) { - ObjectDefineProperty(options, 'hour', {value: 'numeric', - writable: true, - enumerable: true, - configurable: true}); - ObjectDefineProperty(options, 'minute', {value: 'numeric', - writable: true, - enumerable: true, - configurable: true}); - ObjectDefineProperty(options, 'second', {value: 'numeric', + %object_define_property(options, 'year', {value: 'numeric', + writable: true, + enumerable: true, + configurable: true}); + %object_define_property(options, 'month', {value: 'numeric', + writable: true, + enumerable: true, + configurable: true}); + %object_define_property(options, 'day', {value: 'numeric', writable: true, enumerable: true, configurable: true}); } + if (needsDefault && (defaults === 'time' || defaults === 'all')) { + %object_define_property(options, 'hour', {value: 'numeric', + writable: true, + enumerable: true, + configurable: true}); + %object_define_property(options, 'minute', {value: 'numeric', + writable: true, + enumerable: true, + configurable: true}); + %object_define_property(options, 'second', {value: 'numeric', + writable: true, + enumerable: true, + configurable: true}); + } + return options; } @@ -1548,7 +1603,7 @@ function toDateTimeOptions(options, required, defaults) { function initializeDateTimeFormat(dateFormat, locales, options) { if (%IsInitializedIntlObject(dateFormat)) { - throw MakeTypeError(kReinitializeIntl, "DateTimeFormat"); + throw %make_type_error(kReinitializeIntl, "DateTimeFormat"); } if (IS_UNDEFINED(options)) { @@ -1592,7 +1647,7 @@ function initializeDateTimeFormat(dateFormat, locales, options) { getOption, internalOptions); var requestedLocale = locale.locale + extension; - var resolved = ObjectDefineProperties({}, { + var resolved = %object_define_properties({}, { calendar: {writable: true}, day: {writable: true}, era: {writable: true}, @@ -1603,7 +1658,6 @@ function initializeDateTimeFormat(dateFormat, locales, options) { month: {writable: true}, numberingSystem: {writable: true}, [patternSymbol]: {writable: true}, - pattern: patternAccessor, requestedLocale: {value: requestedLocale, writable: true}, second: {writable: true}, timeZone: {writable: true}, @@ -1617,12 +1671,15 @@ function initializeDateTimeFormat(dateFormat, locales, options) { requestedLocale, {skeleton: ldmlString, timeZone: tz}, resolved); if (resolved.timeZone === "Etc/Unknown") { - throw MakeRangeError(kUnsupportedTimeZone, tz); + throw %make_range_error(kUnsupportedTimeZone, tz); } %MarkAsInitializedIntlObjectOfType(dateFormat, 'dateformat', formatter); dateFormat[resolvedSymbol] = resolved; - ObjectDefineProperty(dateFormat, 'resolved', resolvedAccessor); + if (FLAG_intl_extra) { + %object_define_property(resolved, 'pattern', patternAccessor); + %object_define_property(dateFormat, 'resolved', resolvedAccessor); + } return dateFormat; } @@ -1653,29 +1710,21 @@ InstallConstructor(Intl, 'DateTimeFormat', function() { */ InstallFunction(Intl.DateTimeFormat.prototype, 'resolvedOptions', function() { if (!IS_UNDEFINED(new.target)) { - throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor); + throw %make_type_error(kOrdinaryFunctionCalledAsConstructor); } if (!%IsInitializedIntlObjectOfType(this, 'dateformat')) { - throw MakeTypeError(kResolvedOptionsCalledOnNonObject, "DateTimeFormat"); + throw %make_type_error(kResolvedOptionsCalledOnNonObject, "DateTimeFormat"); } /** - * Maps ICU calendar names into LDML type. + * Maps ICU calendar names to LDML/BCP47 types for key 'ca'. + * See typeMap section in third_party/icu/source/data/misc/keyTypeData.txt + * and + * http://www.unicode.org/repos/cldr/tags/latest/common/bcp47/calendar.xml */ var ICU_CALENDAR_MAP = { 'gregorian': 'gregory', - 'japanese': 'japanese', - 'buddhist': 'buddhist', - 'roc': 'roc', - 'persian': 'persian', - 'islamic-civil': 'islamicc', - 'islamic': 'islamic', - 'hebrew': 'hebrew', - 'chinese': 'chinese', - 'indian': 'indian', - 'coptic': 'coptic', - 'ethiopic': 'ethiopic', 'ethiopic-amete-alem': 'ethioaa' }; @@ -1683,8 +1732,7 @@ InstallFunction(Intl.DateTimeFormat.prototype, 'resolvedOptions', function() { var fromPattern = fromLDMLString(format[resolvedSymbol][patternSymbol]); var userCalendar = ICU_CALENDAR_MAP[format[resolvedSymbol].calendar]; if (IS_UNDEFINED(userCalendar)) { - // Use ICU name if we don't have a match. It shouldn't happen, but - // it would be too strict to throw for this. + // No match means that ICU's legacy name is identical to LDML/BCP type. userCalendar = format[resolvedSymbol].calendar; } @@ -1722,7 +1770,7 @@ InstallFunction(Intl.DateTimeFormat.prototype, 'resolvedOptions', function() { */ InstallFunction(Intl.DateTimeFormat, 'supportedLocalesOf', function(locales) { if (!IS_UNDEFINED(new.target)) { - throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor); + throw %make_type_error(kOrdinaryFunctionCalledAsConstructor); } return supportedLocalesOf('dateformat', locales, arguments[1]); @@ -1743,7 +1791,7 @@ function formatDate(formatter, dateValue) { dateMs = TO_NUMBER(dateValue); } - if (!IsFinite(dateMs)) throw MakeRangeError(kDateRange); + if (!NUMBER_IS_FINITE(dateMs)) throw %make_range_error(kDateRange); return %InternalDateFormat(%GetImplFromInitializedIntlObject(formatter), new GlobalDate(dateMs)); @@ -1756,15 +1804,14 @@ function formatDate(formatter, dateValue) { * DateTimeFormat. * Returns undefined if date string cannot be parsed. */ -function parseDate(formatter, value) { +function IntlParseDate(formatter, value) { return %InternalDateParse(%GetImplFromInitializedIntlObject(formatter), - GlobalString(value)); + TO_STRING(value)); } // 0 because date is optional argument. -AddBoundMethod(Intl.DateTimeFormat, 'format', formatDate, 0); -AddBoundMethod(Intl.DateTimeFormat, 'v8Parse', parseDate, 1); +AddBoundMethod(Intl.DateTimeFormat, 'format', formatDate, 0, 'dateformat'); /** @@ -1777,6 +1824,9 @@ function canonicalizeTimeZoneID(tzID) { return tzID; } + // Convert zone name to string. + tzID = TO_STRING(tzID); + // Special case handling (UTC, GMT). var upperID = %StringToUpperCase(tzID); if (upperID === 'UTC' || upperID === 'GMT' || @@ -1789,13 +1839,13 @@ function canonicalizeTimeZoneID(tzID) { // We expect only _, '-' and / beside ASCII letters. // All inputs should conform to Area/Location(/Location)* from now on. var match = InternalRegExpMatch(GetTimezoneNameCheckRE(), tzID); - if (IS_NULL(match)) throw MakeRangeError(kExpectedTimezoneID, tzID); + if (IS_NULL(match)) throw %make_range_error(kExpectedTimezoneID, tzID); var result = toTitleCaseTimezoneLocation(match[1]) + '/' + toTitleCaseTimezoneLocation(match[2]); if (!IS_UNDEFINED(match[3]) && 3 < match.length) { - var locations = %_Call(StringSplit, match[3], '/'); + var locations = %StringSplit(match[3], '/', kMaxUint32); // The 1st element is empty. Starts with i=1. for (var i = 1; i < locations.length; i++) { result = result + '/' + toTitleCaseTimezoneLocation(locations[i]); @@ -1811,7 +1861,7 @@ function canonicalizeTimeZoneID(tzID) { */ function initializeBreakIterator(iterator, locales, options) { if (%IsInitializedIntlObject(iterator)) { - throw MakeTypeError(kReinitializeIntl, "v8BreakIterator"); + throw %make_type_error(kReinitializeIntl, "v8BreakIterator"); } if (IS_UNDEFINED(options)) { @@ -1826,7 +1876,7 @@ function initializeBreakIterator(iterator, locales, options) { 'type', 'string', ['character', 'word', 'sentence', 'line'], 'word')); var locale = resolveLocale('breakiterator', locales, options); - var resolved = ObjectDefineProperties({}, { + var resolved = %object_define_properties({}, { requestedLocale: {value: locale.locale, writable: true}, type: {value: internalOptions.type, writable: true}, locale: {writable: true} @@ -1839,7 +1889,9 @@ function initializeBreakIterator(iterator, locales, options) { %MarkAsInitializedIntlObjectOfType(iterator, 'breakiterator', internalIterator); iterator[resolvedSymbol] = resolved; - ObjectDefineProperty(iterator, 'resolved', resolvedAccessor); + if (FLAG_intl_extra) { + %object_define_property(iterator, 'resolved', resolvedAccessor); + } return iterator; } @@ -1871,11 +1923,11 @@ InstallConstructor(Intl, 'v8BreakIterator', function() { InstallFunction(Intl.v8BreakIterator.prototype, 'resolvedOptions', function() { if (!IS_UNDEFINED(new.target)) { - throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor); + throw %make_type_error(kOrdinaryFunctionCalledAsConstructor); } if (!%IsInitializedIntlObjectOfType(this, 'breakiterator')) { - throw MakeTypeError(kResolvedOptionsCalledOnNonObject, "v8BreakIterator"); + throw %make_type_error(kResolvedOptionsCalledOnNonObject, "v8BreakIterator"); } var segmenter = this; @@ -1900,7 +1952,7 @@ InstallFunction(Intl.v8BreakIterator.prototype, 'resolvedOptions', InstallFunction(Intl.v8BreakIterator, 'supportedLocalesOf', function(locales) { if (!IS_UNDEFINED(new.target)) { - throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor); + throw %make_type_error(kOrdinaryFunctionCalledAsConstructor); } return supportedLocalesOf('breakiterator', locales, arguments[1]); @@ -1914,7 +1966,7 @@ InstallFunction(Intl.v8BreakIterator, 'supportedLocalesOf', */ function adoptText(iterator, text) { %BreakIteratorAdoptText(%GetImplFromInitializedIntlObject(iterator), - GlobalString(text)); + TO_STRING(text)); } @@ -1950,11 +2002,13 @@ function breakType(iterator) { } -AddBoundMethod(Intl.v8BreakIterator, 'adoptText', adoptText, 1); -AddBoundMethod(Intl.v8BreakIterator, 'first', first, 0); -AddBoundMethod(Intl.v8BreakIterator, 'next', next, 0); -AddBoundMethod(Intl.v8BreakIterator, 'current', current, 0); -AddBoundMethod(Intl.v8BreakIterator, 'breakType', breakType, 0); +AddBoundMethod(Intl.v8BreakIterator, 'adoptText', adoptText, 1, + 'breakiterator'); +AddBoundMethod(Intl.v8BreakIterator, 'first', first, 0, 'breakiterator'); +AddBoundMethod(Intl.v8BreakIterator, 'next', next, 0, 'breakiterator'); +AddBoundMethod(Intl.v8BreakIterator, 'current', current, 0, 'breakiterator'); +AddBoundMethod(Intl.v8BreakIterator, 'breakType', breakType, 0, + 'breakiterator'); // Save references to Intl objects and methods we use, for added security. var savedObjects = { @@ -1976,6 +2030,23 @@ var defaultObjects = { 'dateformattime': UNDEFINED, }; +function clearDefaultObjects() { + defaultObjects['dateformatall'] = UNDEFINED; + defaultObjects['dateformatdate'] = UNDEFINED; + defaultObjects['dateformattime'] = UNDEFINED; +} + +var date_cache_version = 0; + +function checkDateCacheCurrent() { + var new_date_cache_version = %DateCacheVersion(); + if (new_date_cache_version == date_cache_version) { + return; + } + date_cache_version = new_date_cache_version; + + clearDefaultObjects(); +} /** * Returns cached or newly created instance of a given service. @@ -1984,6 +2055,7 @@ var defaultObjects = { function cachedOrNewService(service, locales, options, defaults) { var useOptions = (IS_UNDEFINED(defaults)) ? options : defaults; if (IS_UNDEFINED(locales) && IS_UNDEFINED(options)) { + checkDateCacheCurrent(); if (IS_UNDEFINED(defaultObjects[service])) { defaultObjects[service] = new savedObjects[service](locales, useOptions); } @@ -1992,17 +2064,48 @@ function cachedOrNewService(service, locales, options, defaults) { return new savedObjects[service](locales, useOptions); } +function LocaleConvertCase(s, locales, isToUpper) { + // ECMA 402 section 13.1.2 steps 1 through 12. + var language; + // Optimize for the most common two cases. initializeLocaleList() can handle + // them as well, but it's rather slow accounting for over 60% of + // toLocale{U,L}Case() and about 40% of toLocale{U,L}Case("<locale>"). + if (IS_UNDEFINED(locales)) { + language = GetDefaultICULocaleJS(); + } else if (IS_STRING(locales)) { + language = canonicalizeLanguageTag(locales); + } else { + var locales = initializeLocaleList(locales); + language = locales.length > 0 ? locales[0] : GetDefaultICULocaleJS(); + } + + // StringSplit is slower than this. + var pos = %_Call(StringIndexOf, language, '-'); + if (pos != -1) { + language = %_Call(StringSubstring, language, 0, pos); + } + + var CUSTOM_CASE_LANGUAGES = ['az', 'el', 'lt', 'tr']; + var langIndex = %ArrayIndexOf(CUSTOM_CASE_LANGUAGES, language, 0); + if (langIndex == -1) { + // language-independent case conversion. + return isToUpper ? %StringToUpperCaseI18N(s) : %StringToLowerCaseI18N(s); + } + return %StringLocaleConvertCase(s, isToUpper, + CUSTOM_CASE_LANGUAGES[langIndex]); +} + /** * Compares this and that, and returns less than 0, 0 or greater than 0 value. * Overrides the built-in method. */ OverrideFunction(GlobalString.prototype, 'localeCompare', function(that) { if (!IS_UNDEFINED(new.target)) { - throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor); + throw %make_type_error(kOrdinaryFunctionCalledAsConstructor); } if (IS_NULL_OR_UNDEFINED(this)) { - throw MakeTypeError(kMethodInvokedOnNullOrUndefined); + throw %make_type_error(kMethodInvokedOnNullOrUndefined); } var locales = arguments[1]; @@ -2023,7 +2126,7 @@ OverrideFunction(GlobalString.prototype, 'localeCompare', function(that) { OverrideFunction(GlobalString.prototype, 'normalize', function() { if (!IS_UNDEFINED(new.target)) { - throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor); + throw %make_type_error(kOrdinaryFunctionCalledAsConstructor); } CHECK_OBJECT_COERCIBLE(this, "String.prototype.normalize"); @@ -2034,9 +2137,9 @@ OverrideFunction(GlobalString.prototype, 'normalize', function() { var NORMALIZATION_FORMS = ['NFC', 'NFD', 'NFKC', 'NFKD']; - var normalizationForm = %_Call(ArrayIndexOf, NORMALIZATION_FORMS, form); + var normalizationForm = %ArrayIndexOf(NORMALIZATION_FORMS, form, 0); if (normalizationForm === -1) { - throw MakeRangeError(kNormalizationForm, + throw %make_range_error(kNormalizationForm, %_Call(ArrayJoin, NORMALIZATION_FORMS, ', ')); } @@ -2044,6 +2147,56 @@ OverrideFunction(GlobalString.prototype, 'normalize', function() { } ); +function ToLowerCaseI18N() { + if (!IS_UNDEFINED(new.target)) { + throw %make_type_error(kOrdinaryFunctionCalledAsConstructor); + } + CHECK_OBJECT_COERCIBLE(this, "String.prototype.toLowerCase"); + var s = TO_STRING(this); + return %StringToLowerCaseI18N(s); +} + +function ToUpperCaseI18N() { + if (!IS_UNDEFINED(new.target)) { + throw %make_type_error(kOrdinaryFunctionCalledAsConstructor); + } + CHECK_OBJECT_COERCIBLE(this, "String.prototype.toUpperCase"); + var s = TO_STRING(this); + return %StringToUpperCaseI18N(s); +} + +function ToLocaleLowerCaseI18N(locales) { + if (!IS_UNDEFINED(new.target)) { + throw %make_type_error(kOrdinaryFunctionCalledAsConstructor); + } + CHECK_OBJECT_COERCIBLE(this, "String.prototype.toLocaleLowerCase"); + return LocaleConvertCase(TO_STRING(this), locales, false); +} + +%FunctionSetLength(ToLocaleLowerCaseI18N, 0); + +function ToLocaleUpperCaseI18N(locales) { + if (!IS_UNDEFINED(new.target)) { + throw %make_type_error(kOrdinaryFunctionCalledAsConstructor); + } + CHECK_OBJECT_COERCIBLE(this, "String.prototype.toLocaleUpperCase"); + return LocaleConvertCase(TO_STRING(this), locales, true); +} + +%FunctionSetLength(ToLocaleUpperCaseI18N, 0); + +%FunctionRemovePrototype(ToLowerCaseI18N); +%FunctionRemovePrototype(ToUpperCaseI18N); +%FunctionRemovePrototype(ToLocaleLowerCaseI18N); +%FunctionRemovePrototype(ToLocaleUpperCaseI18N); + +utils.Export(function(to) { + to.ToLowerCaseI18N = ToLowerCaseI18N; + to.ToUpperCaseI18N = ToUpperCaseI18N; + to.ToLocaleLowerCaseI18N = ToLocaleLowerCaseI18N; + to.ToLocaleUpperCaseI18N = ToLocaleUpperCaseI18N; +}); + /** * Formats a Number object (this) using locale and options values. @@ -2051,11 +2204,11 @@ OverrideFunction(GlobalString.prototype, 'normalize', function() { */ OverrideFunction(GlobalNumber.prototype, 'toLocaleString', function() { if (!IS_UNDEFINED(new.target)) { - throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor); + throw %make_type_error(kOrdinaryFunctionCalledAsConstructor); } if (!(this instanceof GlobalNumber) && typeof(this) !== 'number') { - throw MakeTypeError(kMethodInvokedOnWrongType, "Number"); + throw %make_type_error(kMethodInvokedOnWrongType, "Number"); } var locales = arguments[0]; @@ -2071,7 +2224,7 @@ OverrideFunction(GlobalNumber.prototype, 'toLocaleString', function() { */ function toLocaleDateTime(date, locales, options, required, defaults, service) { if (!(date instanceof GlobalDate)) { - throw MakeTypeError(kMethodInvokedOnWrongType, "Date"); + throw %make_type_error(kMethodInvokedOnWrongType, "Date"); } if (IsNaN(date)) return 'Invalid Date'; @@ -2092,7 +2245,7 @@ function toLocaleDateTime(date, locales, options, required, defaults, service) { */ OverrideFunction(GlobalDate.prototype, 'toLocaleString', function() { if (!IS_UNDEFINED(new.target)) { - throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor); + throw %make_type_error(kOrdinaryFunctionCalledAsConstructor); } var locales = arguments[0]; @@ -2110,7 +2263,7 @@ OverrideFunction(GlobalDate.prototype, 'toLocaleString', function() { */ OverrideFunction(GlobalDate.prototype, 'toLocaleDateString', function() { if (!IS_UNDEFINED(new.target)) { - throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor); + throw %make_type_error(kOrdinaryFunctionCalledAsConstructor); } var locales = arguments[0]; @@ -2128,7 +2281,7 @@ OverrideFunction(GlobalDate.prototype, 'toLocaleDateString', function() { */ OverrideFunction(GlobalDate.prototype, 'toLocaleTimeString', function() { if (!IS_UNDEFINED(new.target)) { - throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor); + throw %make_type_error(kOrdinaryFunctionCalledAsConstructor); } var locales = arguments[0]; @@ -2138,4 +2291,10 @@ OverrideFunction(GlobalDate.prototype, 'toLocaleTimeString', function() { } ); +utils.Export(function(to) { + to.AddBoundMethod = AddBoundMethod; + to.IntlParseDate = IntlParseDate; + to.IntlParseNumber = IntlParseNumber; +}); + }) |