diff options
Diffstat (limited to 'js/src/builtin')
-rw-r--r-- | js/src/builtin/Array.js | 21 | ||||
-rw-r--r-- | js/src/builtin/Intl.cpp | 801 | ||||
-rw-r--r-- | js/src/builtin/Intl.h | 58 | ||||
-rw-r--r-- | js/src/builtin/Intl.js | 478 | ||||
-rw-r--r-- | js/src/builtin/IntlTimeZoneData.h | 2 | ||||
-rw-r--r-- | js/src/builtin/Map.js | 6 | ||||
-rw-r--r-- | js/src/builtin/Set.js | 6 | ||||
-rw-r--r-- | js/src/builtin/String.js | 15 | ||||
-rw-r--r-- | js/src/builtin/TestingFunctions.cpp | 34 | ||||
-rw-r--r-- | js/src/builtin/TypedArray.js | 8 |
10 files changed, 514 insertions, 915 deletions
diff --git a/js/src/builtin/Array.js b/js/src/builtin/Array.js index 45f90a7b8..30e6fb35f 100644 --- a/js/src/builtin/Array.js +++ b/js/src/builtin/Array.js @@ -711,13 +711,14 @@ function CreateArrayIterator(obj, kind) { // http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%arrayiteratorprototype%.next function ArrayIteratorNext() { // Step 1-3. - if (!IsObject(this) || !IsArrayIterator(this)) { + var obj; + if (!IsObject(this) || (obj = GuardToArrayIterator(this)) === null) { return callFunction(CallArrayIteratorMethodIfWrapped, this, "ArrayIteratorNext"); } // Step 4. - var a = UnsafeGetReservedSlot(this, ITERATOR_SLOT_TARGET); + var a = UnsafeGetReservedSlot(obj, ITERATOR_SLOT_TARGET); var result = { value: undefined, done: false }; // Step 5. @@ -728,10 +729,10 @@ function ArrayIteratorNext() { // Step 6. // The index might not be an integer, so we have to do a generic get here. - var index = UnsafeGetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX); + var index = UnsafeGetReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX); // Step 7. - var itemKind = UnsafeGetInt32FromReservedSlot(this, ITERATOR_SLOT_ITEM_KIND); + var itemKind = UnsafeGetInt32FromReservedSlot(obj, ITERATOR_SLOT_ITEM_KIND); // Step 8-9. var len = IsPossiblyWrappedTypedArray(a) @@ -740,13 +741,13 @@ function ArrayIteratorNext() { // Step 10. if (index >= len) { - UnsafeSetReservedSlot(this, ITERATOR_SLOT_TARGET, null); + UnsafeSetReservedSlot(obj, ITERATOR_SLOT_TARGET, null); result.done = true; return result; } // Step 11. - UnsafeSetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX, index + 1); + UnsafeSetReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX, index + 1); // Step 16. if (itemKind === ITEM_KIND_VALUE) { @@ -900,11 +901,7 @@ function ArrayToLocaleString(locales, options) { if (firstElement === undefined || firstElement === null) { R = ""; } else { -#if EXPOSE_INTL_API R = ToString(callContentFunction(firstElement.toLocaleString, firstElement, locales, options)); -#else - R = ToString(callContentFunction(firstElement.toLocaleString, firstElement)); -#endif } // Step 3 (reordered). @@ -919,11 +916,7 @@ function ArrayToLocaleString(locales, options) { // Steps 9.a, 9.c-e. R += separator; if (!(nextElement === undefined || nextElement === null)) { -#if EXPOSE_INTL_API R += ToString(callContentFunction(nextElement.toLocaleString, nextElement, locales, options)); -#else - R += ToString(callContentFunction(nextElement.toLocaleString, nextElement)); -#endif } } diff --git a/js/src/builtin/Intl.cpp b/js/src/builtin/Intl.cpp index 3a20c487b..71f7b58d4 100644 --- a/js/src/builtin/Intl.cpp +++ b/js/src/builtin/Intl.cpp @@ -23,7 +23,6 @@ #include "jsobj.h" #include "builtin/IntlTimeZoneData.h" -#if ENABLE_INTL_API #include "unicode/ucal.h" #include "unicode/ucol.h" #include "unicode/udat.h" @@ -32,7 +31,6 @@ #include "unicode/unum.h" #include "unicode/unumsys.h" #include "unicode/ustring.h" -#endif #include "vm/DateTime.h" #include "vm/GlobalObject.h" #include "vm/Interpreter.h" @@ -60,512 +58,6 @@ using mozilla::PodCopy; * http://userguide.icu-project.org/design#TOC-Error-Handling */ - -/******************** ICU stubs ********************/ - -#if !ENABLE_INTL_API - -/* - * When the Internationalization API isn't enabled, we also shouldn't link - * against ICU. However, we still want to compile this code in order to prevent - * bit rot. The following stub implementations for ICU functions make this - * possible. The functions using them should never be called, so they assert - * and return error codes. Signatures adapted from ICU header files locid.h, - * numsys.h, ucal.h, ucol.h, udat.h, udatpg.h, uenum.h, unum.h; see the ICU - * directory for license. - */ - -typedef bool UBool; -typedef char16_t UChar; -typedef double UDate; - -enum UErrorCode { - U_ZERO_ERROR, - U_BUFFER_OVERFLOW_ERROR, -}; - -static inline UBool -U_FAILURE(UErrorCode code) -{ - MOZ_CRASH("U_FAILURE: Intl API disabled"); -} - -inline const UChar* -Char16ToUChar(const char16_t* chars) -{ - MOZ_CRASH("Char16ToUChar: Intl API disabled"); -} - -inline UChar* -Char16ToUChar(char16_t* chars) -{ - MOZ_CRASH("Char16ToUChar: Intl API disabled"); -} - -static int32_t -u_strlen(const UChar* s) -{ - MOZ_CRASH("u_strlen: Intl API disabled"); -} - -struct UEnumeration; - -static int32_t -uenum_count(UEnumeration* en, UErrorCode* status) -{ - MOZ_CRASH("uenum_count: Intl API disabled"); -} - -static const char* -uenum_next(UEnumeration* en, int32_t* resultLength, UErrorCode* status) -{ - MOZ_CRASH("uenum_next: Intl API disabled"); -} - -static void -uenum_close(UEnumeration* en) -{ - MOZ_CRASH("uenum_close: Intl API disabled"); -} - -struct UCollator; - -enum UColAttribute { - UCOL_ALTERNATE_HANDLING, - UCOL_CASE_FIRST, - UCOL_CASE_LEVEL, - UCOL_NORMALIZATION_MODE, - UCOL_STRENGTH, - UCOL_NUMERIC_COLLATION, -}; - -enum UColAttributeValue { - UCOL_DEFAULT = -1, - UCOL_PRIMARY = 0, - UCOL_SECONDARY = 1, - UCOL_TERTIARY = 2, - UCOL_OFF = 16, - UCOL_ON = 17, - UCOL_SHIFTED = 20, - UCOL_LOWER_FIRST = 24, - UCOL_UPPER_FIRST = 25, -}; - -enum UCollationResult { - UCOL_EQUAL = 0, - UCOL_GREATER = 1, - UCOL_LESS = -1 -}; - -static int32_t -ucol_countAvailable() -{ - MOZ_CRASH("ucol_countAvailable: Intl API disabled"); -} - -static const char* -ucol_getAvailable(int32_t localeIndex) -{ - MOZ_CRASH("ucol_getAvailable: Intl API disabled"); -} - -static UCollator* -ucol_open(const char* loc, UErrorCode* status) -{ - MOZ_CRASH("ucol_open: Intl API disabled"); -} - -static void -ucol_setAttribute(UCollator* coll, UColAttribute attr, UColAttributeValue value, UErrorCode* status) -{ - MOZ_CRASH("ucol_setAttribute: Intl API disabled"); -} - -static UCollationResult -ucol_strcoll(const UCollator* coll, const UChar* source, int32_t sourceLength, - const UChar* target, int32_t targetLength) -{ - MOZ_CRASH("ucol_strcoll: Intl API disabled"); -} - -static void -ucol_close(UCollator* coll) -{ - MOZ_CRASH("ucol_close: Intl API disabled"); -} - -static UEnumeration* -ucol_getKeywordValuesForLocale(const char* key, const char* locale, UBool commonlyUsed, - UErrorCode* status) -{ - MOZ_CRASH("ucol_getKeywordValuesForLocale: Intl API disabled"); -} - -struct UParseError; -struct UFieldPosition; -struct UFieldPositionIterator; -typedef void* UNumberFormat; - -enum UNumberFormatStyle { - UNUM_DECIMAL = 1, - UNUM_CURRENCY, - UNUM_PERCENT, - UNUM_CURRENCY_ISO, - UNUM_CURRENCY_PLURAL, -}; - -enum UNumberFormatRoundingMode { - UNUM_ROUND_HALFUP, -}; - -enum UNumberFormatAttribute { - UNUM_GROUPING_USED, - UNUM_MIN_INTEGER_DIGITS, - UNUM_MAX_FRACTION_DIGITS, - UNUM_MIN_FRACTION_DIGITS, - UNUM_ROUNDING_MODE, - UNUM_SIGNIFICANT_DIGITS_USED, - UNUM_MIN_SIGNIFICANT_DIGITS, - UNUM_MAX_SIGNIFICANT_DIGITS, -}; - -enum UNumberFormatTextAttribute { - UNUM_CURRENCY_CODE, -}; - -static int32_t -unum_countAvailable() -{ - MOZ_CRASH("unum_countAvailable: Intl API disabled"); -} - -static const char* -unum_getAvailable(int32_t localeIndex) -{ - MOZ_CRASH("unum_getAvailable: Intl API disabled"); -} - -static UNumberFormat* -unum_open(UNumberFormatStyle style, const UChar* pattern, int32_t patternLength, - const char* locale, UParseError* parseErr, UErrorCode* status) -{ - MOZ_CRASH("unum_open: Intl API disabled"); -} - -static void -unum_setAttribute(UNumberFormat* fmt, UNumberFormatAttribute attr, int32_t newValue) -{ - MOZ_CRASH("unum_setAttribute: Intl API disabled"); -} - -static int32_t -unum_formatDouble(const UNumberFormat* fmt, double number, UChar* result, - int32_t resultLength, UFieldPosition* pos, UErrorCode* status) -{ - MOZ_CRASH("unum_formatDouble: Intl API disabled"); -} - -static void -unum_close(UNumberFormat* fmt) -{ - MOZ_CRASH("unum_close: Intl API disabled"); -} - -static void -unum_setTextAttribute(UNumberFormat* fmt, UNumberFormatTextAttribute tag, const UChar* newValue, - int32_t newValueLength, UErrorCode* status) -{ - MOZ_CRASH("unum_setTextAttribute: Intl API disabled"); -} - -typedef void* UNumberingSystem; - -static UNumberingSystem* -unumsys_open(const char* locale, UErrorCode* status) -{ - MOZ_CRASH("unumsys_open: Intl API disabled"); -} - -static const char* -unumsys_getName(const UNumberingSystem* unumsys) -{ - MOZ_CRASH("unumsys_getName: Intl API disabled"); -} - -static void -unumsys_close(UNumberingSystem* unumsys) -{ - MOZ_CRASH("unumsys_close: Intl API disabled"); -} - -typedef void* UCalendar; - -enum UCalendarType { - UCAL_TRADITIONAL, - UCAL_DEFAULT = UCAL_TRADITIONAL, - UCAL_GREGORIAN -}; - -enum UCalendarAttribute { - UCAL_FIRST_DAY_OF_WEEK, - UCAL_MINIMAL_DAYS_IN_FIRST_WEEK -}; - -enum UCalendarDaysOfWeek { - UCAL_SUNDAY, - UCAL_MONDAY, - UCAL_TUESDAY, - UCAL_WEDNESDAY, - UCAL_THURSDAY, - UCAL_FRIDAY, - UCAL_SATURDAY -}; - -enum UCalendarWeekdayType { - UCAL_WEEKDAY, - UCAL_WEEKEND, - UCAL_WEEKEND_ONSET, - UCAL_WEEKEND_CEASE -}; - -enum UCalendarDateFields { - UCAL_ERA, - UCAL_YEAR, - UCAL_MONTH, - UCAL_WEEK_OF_YEAR, - UCAL_WEEK_OF_MONTH, - UCAL_DATE, - UCAL_DAY_OF_YEAR, - UCAL_DAY_OF_WEEK, - UCAL_DAY_OF_WEEK_IN_MONTH, - UCAL_AM_PM, - UCAL_HOUR, - UCAL_HOUR_OF_DAY, - UCAL_MINUTE, - UCAL_SECOND, - UCAL_MILLISECOND, - UCAL_ZONE_OFFSET, - UCAL_DST_OFFSET, - UCAL_YEAR_WOY, - UCAL_DOW_LOCAL, - UCAL_EXTENDED_YEAR, - UCAL_JULIAN_DAY, - UCAL_MILLISECONDS_IN_DAY, - UCAL_IS_LEAP_MONTH, - UCAL_FIELD_COUNT, - UCAL_DAY_OF_MONTH = UCAL_DATE -}; - -static UCalendar* -ucal_open(const UChar* zoneID, int32_t len, const char* locale, - UCalendarType type, UErrorCode* status) -{ - MOZ_CRASH("ucal_open: Intl API disabled"); -} - -static const char* -ucal_getType(const UCalendar* cal, UErrorCode* status) -{ - MOZ_CRASH("ucal_getType: Intl API disabled"); -} - -static UEnumeration* -ucal_getKeywordValuesForLocale(const char* key, const char* locale, - UBool commonlyUsed, UErrorCode* status) -{ - MOZ_CRASH("ucal_getKeywordValuesForLocale: Intl API disabled"); -} - -static void -ucal_close(UCalendar* cal) -{ - MOZ_CRASH("ucal_close: Intl API disabled"); -} - -static UCalendarWeekdayType -ucal_getDayOfWeekType(const UCalendar *cal, UCalendarDaysOfWeek dayOfWeek, UErrorCode* status) -{ - MOZ_CRASH("ucal_getDayOfWeekType: Intl API disabled"); -} - -static int32_t -ucal_getAttribute(const UCalendar* cal, - UCalendarAttribute attr) -{ - MOZ_CRASH("ucal_getAttribute: Intl API disabled"); -} - -static int32_t -ucal_get(const UCalendar *cal, UCalendarDateFields field, UErrorCode *status) -{ - MOZ_CRASH("ucal_get: Intl API disabled"); -} - -static UEnumeration* -ucal_openTimeZones(UErrorCode* status) -{ - MOZ_CRASH("ucal_openTimeZones: Intl API disabled"); -} - -static int32_t -ucal_getCanonicalTimeZoneID(const UChar* id, int32_t len, UChar* result, int32_t resultCapacity, - UBool* isSystemID, UErrorCode* status) -{ - MOZ_CRASH("ucal_getCanonicalTimeZoneID: Intl API disabled"); -} - -static int32_t -ucal_getDefaultTimeZone(UChar* result, int32_t resultCapacity, UErrorCode* status) -{ - MOZ_CRASH("ucal_getDefaultTimeZone: Intl API disabled"); -} - -typedef void* UDateTimePatternGenerator; - -static UDateTimePatternGenerator* -udatpg_open(const char* locale, UErrorCode* pErrorCode) -{ - MOZ_CRASH("udatpg_open: Intl API disabled"); -} - -static int32_t -udatpg_getBestPattern(UDateTimePatternGenerator* dtpg, const UChar* skeleton, - int32_t length, UChar* bestPattern, int32_t capacity, - UErrorCode* pErrorCode) -{ - MOZ_CRASH("udatpg_getBestPattern: Intl API disabled"); -} - -static void -udatpg_close(UDateTimePatternGenerator* dtpg) -{ - MOZ_CRASH("udatpg_close: Intl API disabled"); -} - -typedef void* UCalendar; -typedef void* UDateFormat; - -enum UDateFormatField { - UDAT_ERA_FIELD = 0, - UDAT_YEAR_FIELD = 1, - UDAT_MONTH_FIELD = 2, - UDAT_DATE_FIELD = 3, - UDAT_HOUR_OF_DAY1_FIELD = 4, - UDAT_HOUR_OF_DAY0_FIELD = 5, - UDAT_MINUTE_FIELD = 6, - UDAT_SECOND_FIELD = 7, - UDAT_FRACTIONAL_SECOND_FIELD = 8, - UDAT_DAY_OF_WEEK_FIELD = 9, - UDAT_DAY_OF_YEAR_FIELD = 10, - UDAT_DAY_OF_WEEK_IN_MONTH_FIELD = 11, - UDAT_WEEK_OF_YEAR_FIELD = 12, - UDAT_WEEK_OF_MONTH_FIELD = 13, - UDAT_AM_PM_FIELD = 14, - UDAT_HOUR1_FIELD = 15, - UDAT_HOUR0_FIELD = 16, - UDAT_TIMEZONE_FIELD = 17, - UDAT_YEAR_WOY_FIELD = 18, - UDAT_DOW_LOCAL_FIELD = 19, - UDAT_EXTENDED_YEAR_FIELD = 20, - UDAT_JULIAN_DAY_FIELD = 21, - UDAT_MILLISECONDS_IN_DAY_FIELD = 22, - UDAT_TIMEZONE_RFC_FIELD = 23, - UDAT_TIMEZONE_GENERIC_FIELD = 24, - UDAT_STANDALONE_DAY_FIELD = 25, - UDAT_STANDALONE_MONTH_FIELD = 26, - UDAT_QUARTER_FIELD = 27, - UDAT_STANDALONE_QUARTER_FIELD = 28, - UDAT_TIMEZONE_SPECIAL_FIELD = 29, - UDAT_YEAR_NAME_FIELD = 30, - UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD = 31, - UDAT_TIMEZONE_ISO_FIELD = 32, - UDAT_TIMEZONE_ISO_LOCAL_FIELD = 33, - UDAT_RELATED_YEAR_FIELD = 34, - UDAT_AM_PM_MIDNIGHT_NOON_FIELD = 35, - UDAT_FLEXIBLE_DAY_PERIOD_FIELD = 36, - UDAT_TIME_SEPARATOR_FIELD = 37, - UDAT_FIELD_COUNT = 38 -}; - -enum UDateFormatStyle { - UDAT_PATTERN = -2, - UDAT_IGNORE = UDAT_PATTERN -}; - -static int32_t -udat_countAvailable() -{ - MOZ_CRASH("udat_countAvailable: Intl API disabled"); -} - -static const char* -udat_getAvailable(int32_t localeIndex) -{ - MOZ_CRASH("udat_getAvailable: Intl API disabled"); -} - -static UDateFormat* -udat_open(UDateFormatStyle timeStyle, UDateFormatStyle dateStyle, const char* locale, - const UChar* tzID, int32_t tzIDLength, const UChar* pattern, - int32_t patternLength, UErrorCode* status) -{ - MOZ_CRASH("udat_open: Intl API disabled"); -} - -static const UCalendar* -udat_getCalendar(const UDateFormat* fmt) -{ - MOZ_CRASH("udat_getCalendar: Intl API disabled"); -} - -static void -ucal_setGregorianChange(UCalendar* cal, UDate date, UErrorCode* pErrorCode) -{ - MOZ_CRASH("ucal_setGregorianChange: Intl API disabled"); -} - -static int32_t -udat_format(const UDateFormat* format, UDate dateToFormat, UChar* result, - int32_t resultLength, UFieldPosition* position, UErrorCode* status) -{ - MOZ_CRASH("udat_format: Intl API disabled"); -} - -static int32_t -udat_formatForFields(const UDateFormat* format, UDate dateToFormat, - UChar* result, int32_t resultLength, UFieldPositionIterator* fpositer, - UErrorCode* status) -{ - MOZ_CRASH("udat_formatForFields: Intl API disabled"); -} - -static UFieldPositionIterator* -ufieldpositer_open(UErrorCode* status) -{ - MOZ_CRASH("ufieldpositer_open: Intl API disabled"); -} - -static void -ufieldpositer_close(UFieldPositionIterator* fpositer) -{ - MOZ_CRASH("ufieldpositer_close: Intl API disabled"); -} - -static int32_t -ufieldpositer_next(UFieldPositionIterator* fpositer, int32_t* beginIndex, int32_t* endIndex) -{ - MOZ_CRASH("ufieldpositer_next: Intl API disabled"); -} - -static void -udat_close(UDateFormat* format) -{ - MOZ_CRASH("udat_close: Intl API disabled"); -} - -#endif - - /******************** Common to Intl constructors ********************/ static bool @@ -615,7 +107,6 @@ intl_availableLocales(JSContext* cx, CountAvailable countAvailable, if (!locales) return false; -#if ENABLE_INTL_API uint32_t count = countAvailable(); RootedValue t(cx, BooleanValue(true)); for (uint32_t i = 0; i < count; i++) { @@ -635,7 +126,7 @@ intl_availableLocales(JSContext* cx, CountAvailable countAvailable, return false; } } -#endif + result.setObject(*locales); return true; } @@ -2921,6 +2412,296 @@ js::intl_GetCalendarInfo(JSContext* cx, unsigned argc, Value* vp) return true; } +template<size_t N> +inline bool +MatchPart(const char** pattern, const char (&part)[N]) +{ + if (strncmp(*pattern, part, N - 1)) + return false; + + *pattern += N - 1; + return true; +} + +bool +js::intl_ComputeDisplayNames(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + MOZ_ASSERT(args.length() == 3); + // 1. Assert: locale is a string. + MOZ_ASSERT(args[0].isString()); + // 2. Assert: style is a string. + MOZ_ASSERT(args[1].isString()); + // 3. Assert: keys is an Array. + MOZ_ASSERT(args[2].isObject()); + + JSAutoByteString locale(cx, args[0].toString()); + if (!locale) + return false; + + JSAutoByteString style(cx, args[1].toString()); + if (!style) + return false; + + RootedArrayObject keys(cx, &args[2].toObject().as<ArrayObject>()); + if (!keys) + return false; + + // 4. Let result be ArrayCreate(0). + RootedArrayObject result(cx, NewDenseUnallocatedArray(cx, keys->length())); + if (!result) + return false; + + UErrorCode status = U_ZERO_ERROR; + + UDateFormat* fmt = + udat_open(UDAT_DEFAULT, UDAT_DEFAULT, icuLocale(locale.ptr()), + nullptr, 0, nullptr, 0, &status); + if (U_FAILURE(status)) { + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR); + return false; + } + ScopedICUObject<UDateFormat, udat_close> datToClose(fmt); + + // UDateTimePatternGenerator will be needed for translations of date and + // time fields like "month", "week", "day" etc. + UDateTimePatternGenerator* dtpg = udatpg_open(icuLocale(locale.ptr()), &status); + if (U_FAILURE(status)) { + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR); + return false; + } + ScopedICUObject<UDateTimePatternGenerator, udatpg_close> datPgToClose(dtpg); + + RootedValue keyValue(cx); + RootedString keyValStr(cx); + RootedValue wordVal(cx); + Vector<char16_t, INITIAL_CHAR_BUFFER_SIZE> chars(cx); + if (!chars.resize(INITIAL_CHAR_BUFFER_SIZE)) + return false; + + // 5. For each element of keys, + for (uint32_t i = 0; i < keys->length(); i++) { + /** + * We iterate over keys array looking for paths that we have code + * branches for. + * + * For any unknown path branch, the wordVal will keep NullValue and + * we'll throw at the end. + */ + + if (!GetElement(cx, keys, keys, i, &keyValue)) + return false; + + JSAutoByteString pattern; + keyValStr = keyValue.toString(); + if (!pattern.encodeUtf8(cx, keyValStr)) + return false; + + wordVal.setNull(); + + // 5.a. Perform an implementation dependent algorithm to map a key to a + // corresponding display name. + const char* pat = pattern.ptr(); + + if (!MatchPart(&pat, "dates")) { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr()); + return false; + } + + if (!MatchPart(&pat, "/")) { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr()); + return false; + } + + if (MatchPart(&pat, "fields")) { + if (!MatchPart(&pat, "/")) { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr()); + return false; + } + + UDateTimePatternField fieldType; + + if (MatchPart(&pat, "year")) { + fieldType = UDATPG_YEAR_FIELD; + } else if (MatchPart(&pat, "month")) { + fieldType = UDATPG_MONTH_FIELD; + } else if (MatchPart(&pat, "week")) { + fieldType = UDATPG_WEEK_OF_YEAR_FIELD; + } else if (MatchPart(&pat, "day")) { + fieldType = UDATPG_DAY_FIELD; + } else { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr()); + return false; + } + + // This part must be the final part with no trailing data. + if (*pat != '\0') { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr()); + return false; + } + + int32_t resultSize; + + const UChar* value = udatpg_getAppendItemName(dtpg, fieldType, &resultSize); + if (U_FAILURE(status)) { + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR); + return false; + } + + JSString* word = NewStringCopyN<CanGC>(cx, UCharToChar16(value), resultSize); + if (!word) + return false; + + wordVal.setString(word); + } else if (MatchPart(&pat, "gregorian")) { + if (!MatchPart(&pat, "/")) { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr()); + return false; + } + + UDateFormatSymbolType symbolType; + int32_t index; + + if (MatchPart(&pat, "months")) { + if (!MatchPart(&pat, "/")) { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr()); + return false; + } + + if (equal(style, "narrow")) { + symbolType = UDAT_STANDALONE_NARROW_MONTHS; + } else if (equal(style, "short")) { + symbolType = UDAT_STANDALONE_SHORT_MONTHS; + } else { + MOZ_ASSERT(equal(style, "long")); + symbolType = UDAT_STANDALONE_MONTHS; + } + + if (MatchPart(&pat, "january")) { + index = UCAL_JANUARY; + } else if (MatchPart(&pat, "february")) { + index = UCAL_FEBRUARY; + } else if (MatchPart(&pat, "march")) { + index = UCAL_MARCH; + } else if (MatchPart(&pat, "april")) { + index = UCAL_APRIL; + } else if (MatchPart(&pat, "may")) { + index = UCAL_MAY; + } else if (MatchPart(&pat, "june")) { + index = UCAL_JUNE; + } else if (MatchPart(&pat, "july")) { + index = UCAL_JULY; + } else if (MatchPart(&pat, "august")) { + index = UCAL_AUGUST; + } else if (MatchPart(&pat, "september")) { + index = UCAL_SEPTEMBER; + } else if (MatchPart(&pat, "october")) { + index = UCAL_OCTOBER; + } else if (MatchPart(&pat, "november")) { + index = UCAL_NOVEMBER; + } else if (MatchPart(&pat, "december")) { + index = UCAL_DECEMBER; + } else { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr()); + return false; + } + } else if (MatchPart(&pat, "weekdays")) { + if (!MatchPart(&pat, "/")) { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr()); + return false; + } + + if (equal(style, "narrow")) { + symbolType = UDAT_STANDALONE_NARROW_WEEKDAYS; + } else if (equal(style, "short")) { + symbolType = UDAT_STANDALONE_SHORT_WEEKDAYS; + } else { + MOZ_ASSERT(equal(style, "long")); + symbolType = UDAT_STANDALONE_WEEKDAYS; + } + + if (MatchPart(&pat, "monday")) { + index = UCAL_MONDAY; + } else if (MatchPart(&pat, "tuesday")) { + index = UCAL_TUESDAY; + } else if (MatchPart(&pat, "wednesday")) { + index = UCAL_WEDNESDAY; + } else if (MatchPart(&pat, "thursday")) { + index = UCAL_THURSDAY; + } else if (MatchPart(&pat, "friday")) { + index = UCAL_FRIDAY; + } else if (MatchPart(&pat, "saturday")) { + index = UCAL_SATURDAY; + } else if (MatchPart(&pat, "sunday")) { + index = UCAL_SUNDAY; + } else { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr()); + return false; + } + } else if (MatchPart(&pat, "dayperiods")) { + if (!MatchPart(&pat, "/")) { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr()); + return false; + } + + symbolType = UDAT_AM_PMS; + + if (MatchPart(&pat, "am")) { + index = UCAL_AM; + } else if (MatchPart(&pat, "pm")) { + index = UCAL_PM; + } else { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr()); + return false; + } + } else { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr()); + return false; + } + + // This part must be the final part with no trailing data. + if (*pat != '\0') { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr()); + return false; + } + + int32_t resultSize = + udat_getSymbols(fmt, symbolType, index, Char16ToUChar(chars.begin()), + INITIAL_CHAR_BUFFER_SIZE, &status); + if (status == U_BUFFER_OVERFLOW_ERROR) { + if (!chars.resize(resultSize)) + return false; + status = U_ZERO_ERROR; + udat_getSymbols(fmt, symbolType, index, Char16ToUChar(chars.begin()), + resultSize, &status); + } + if (U_FAILURE(status)) { + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR); + return false; + } + + JSString* word = NewStringCopyN<CanGC>(cx, chars.begin(), resultSize); + if (!word) + return false; + + wordVal.setString(word); + } else { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr()); + return false; + } + + MOZ_ASSERT(wordVal.isString()); + + // 5.b. Append the result string to result. + if (!DefineElement(cx, result, i, wordVal)) + return false; + } + + // 6. Return result. + args.rval().setObject(*result); + return true; +} + /******************** Intl ********************/ const Class js::IntlClass = { diff --git a/js/src/builtin/Intl.h b/js/src/builtin/Intl.h index 54764605b..9a1e44913 100644 --- a/js/src/builtin/Intl.h +++ b/js/src/builtin/Intl.h @@ -16,9 +16,7 @@ #include "js/GCAPI.h" #include "js/GCHashTable.h" -#if ENABLE_INTL_API #include "unicode/utypes.h" -#endif /* * The Intl module specified by standard ECMA-402, @@ -387,7 +385,48 @@ intl_FormatDateTime(JSContext* cx, unsigned argc, Value* vp); extern MOZ_MUST_USE bool intl_GetCalendarInfo(JSContext* cx, unsigned argc, Value* vp); -#if ENABLE_INTL_API +/** + * Returns an Array with CLDR-based fields display names. + * The function takes three arguments: + * + * locale + * BCP47 compliant locale string + * style + * A string with values: long or short or narrow + * keys + * An array or path-like strings that identify keys to be returned + * At the moment the following types of keys are supported: + * + * 'dates/fields/{year|month|week|day}' + * 'dates/gregorian/months/{january|...|december}' + * 'dates/gregorian/weekdays/{sunday|...|saturday}' + * 'dates/gregorian/dayperiods/{am|pm}' + * + * Example: + * + * let info = intl_ComputeDisplayNames( + * 'en-US', + * 'long', + * [ + * 'dates/fields/year', + * 'dates/gregorian/months/january', + * 'dates/gregorian/weekdays/monday', + * 'dates/gregorian/dayperiods/am', + * ] + * ); + * + * Returned value: + * + * [ + * 'year', + * 'January', + * 'Monday', + * 'AM' + * ] + */ +extern MOZ_MUST_USE bool +intl_ComputeDisplayNames(JSContext* cx, unsigned argc, Value* vp); + /** * Cast char16_t* strings to UChar* strings used by ICU. */ @@ -402,7 +441,18 @@ Char16ToUChar(char16_t* chars) { return reinterpret_cast<UChar*>(chars); } -#endif // ENABLE_INTL_API + +inline char16_t* +UCharToChar16(UChar* chars) +{ + return reinterpret_cast<char16_t*>(chars); +} + +inline const char16_t* +UCharToChar16(const UChar* chars) +{ + return reinterpret_cast<const char16_t*>(chars); +} } // namespace js diff --git a/js/src/builtin/Intl.js b/js/src/builtin/Intl.js index 37c87365b..6391c3e70 100644 --- a/js/src/builtin/Intl.js +++ b/js/src/builtin/Intl.js @@ -21,9 +21,6 @@ intl_availableCalendars: false, intl_patternForSkeleton: false, intl_FormatDateTime: false, - intl_SelectPluralRule: false, - intl_GetPluralCategories: false, - intl_GetCalendarInfo: false, */ /* @@ -860,7 +857,6 @@ function BestAvailableLocaleIgnoringDefault(availableLocales, locale) { return BestAvailableLocaleHelper(availableLocales, locale, false); } -var noRelevantExtensionKeys = []; /** * Compares a BCP 47 language priority list against the set of locales in @@ -1188,10 +1184,9 @@ function GetOption(options, property, type, values, fallback) { * Spec: ECMAScript Internationalization API Specification, 9.2.10. */ function GetNumberOption(options, property, minimum, maximum, fallback) { - assert(typeof minimum === "number" && (minimum | 0) === minimum, "GetNumberOption"); - assert(typeof maximum === "number" && (maximum | 0) === maximum, "GetNumberOption"); - assert(typeof fallback === "number" && (fallback | 0) === fallback, "GetNumberOption"); - assert(minimum <= fallback && fallback <= maximum, "GetNumberOption"); + assert(typeof minimum === "number", "GetNumberOption"); + assert(typeof maximum === "number", "GetNumberOption"); + assert(fallback === undefined || (fallback >= minimum && fallback <= maximum), "GetNumberOption"); // Step 1. var value = options[property]; @@ -1201,10 +1196,7 @@ function GetNumberOption(options, property, minimum, maximum, fallback) { value = ToNumber(value); if (Number_isNaN(value) || value < minimum || value > maximum) ThrowRangeError(JSMSG_INVALID_DIGITS_VALUE, value); - - // Apply bitwise-or to convert -0 to +0 per ES2017, 5.2 and to ensure - // the result is an int32 value. - return std_Math_floor(value) | 0; + return std_Math_floor(value); } // Step 3. @@ -1278,9 +1270,7 @@ function initializeIntlObject(obj) { function setLazyData(internals, type, lazyData) { assert(internals.type === "partial", "can't set lazy data for anything but a newborn"); - assert(type === "Collator" || type === "DateTimeFormat" || - type == "NumberFormat" || type === "PluralRules", - "bad type"); + assert(type === "Collator" || type === "DateTimeFormat" || type == "NumberFormat", "bad type"); assert(IsObject(lazyData), "non-object lazy data"); // Set in reverse order so that the .type change is a barrier. @@ -1330,9 +1320,7 @@ function isInitializedIntlObject(obj) { if (IsObject(internals)) { assert(callFunction(std_Object_hasOwnProperty, internals, "type"), "missing type"); var type = internals.type; - assert(type === "partial" || type === "Collator" || - type === "DateTimeFormat" || type === "NumberFormat" || type === "PluralRules", - "unexpected type"); + assert(type === "partial" || type === "Collator" || type === "DateTimeFormat" || type === "NumberFormat", "unexpected type"); assert(callFunction(std_Object_hasOwnProperty, internals, "lazyData"), "missing lazyData"); assert(callFunction(std_Object_hasOwnProperty, internals, "internalProps"), "missing internalProps"); } else { @@ -1389,8 +1377,6 @@ function getInternals(obj) internalProps = resolveCollatorInternals(lazyData) else if (type === "DateTimeFormat") internalProps = resolveDateTimeFormatInternals(lazyData) - else if (type === "PluralRules") - internalProps = resolvePluralRulesInternals(lazyData) else internalProps = resolveNumberFormatInternals(lazyData); setInternalProperties(internals, internalProps); @@ -1722,7 +1708,6 @@ function Intl_Collator_compare_get() { // Step 2. return internals.boundCompare; } -_SetCanonicalName(Intl_Collator_compare_get, "get compare"); /** @@ -1791,37 +1776,45 @@ function resolveNumberFormatInternals(lazyNumberFormatData) { // Step 6. var opt = lazyNumberFormatData.opt; + // Compute effective locale. + // Step 9. var NumberFormat = numberFormatInternalProperties; - // Step 9. + // Step 10. var localeData = NumberFormat.localeData; - // Step 10. + // Step 11. var r = ResolveLocale(callFunction(NumberFormat.availableLocales, NumberFormat), lazyNumberFormatData.requestedLocales, lazyNumberFormatData.opt, NumberFormat.relevantExtensionKeys, localeData); - // Steps 11-12. (Step 13 is not relevant to our implementation.) + // Steps 12-13. (Step 14 is not relevant to our implementation.) internalProps.locale = r.locale; internalProps.numberingSystem = r.nu; // Compute formatting options. - // Step 15. - var style = lazyNumberFormatData.style; - internalProps.style = style; + // Step 16. + var s = lazyNumberFormatData.style; + internalProps.style = s; - // Steps 19, 21. - if (style === "currency") { + // Steps 20, 22. + if (s === "currency") { internalProps.currency = lazyNumberFormatData.currency; internalProps.currencyDisplay = lazyNumberFormatData.currencyDisplay; } + // Step 24. internalProps.minimumIntegerDigits = lazyNumberFormatData.minimumIntegerDigits; + + // Steps 27. internalProps.minimumFractionDigits = lazyNumberFormatData.minimumFractionDigits; + + // Step 30. internalProps.maximumFractionDigits = lazyNumberFormatData.maximumFractionDigits; + // Step 33. if ("minimumSignificantDigits" in lazyNumberFormatData) { // Note: Intl.NumberFormat.prototype.resolvedOptions() exposes the // actual presence (versus undefined-ness) of these properties. @@ -1830,10 +1823,10 @@ function resolveNumberFormatInternals(lazyNumberFormatData) { internalProps.maximumSignificantDigits = lazyNumberFormatData.maximumSignificantDigits; } - // Step 27. + // Step 35. internalProps.useGrouping = lazyNumberFormatData.useGrouping; - // Step 34. + // Step 42. internalProps.boundFormat = undefined; // The caller is responsible for associating |internalProps| with the right @@ -1861,44 +1854,6 @@ function getNumberFormatInternals(obj, methodName) { return internalProps; } -/** - * Applies digit options used for number formatting onto the intl object. - * - * Spec: ECMAScript Internationalization API Specification, 11.1.1. - */ -function SetNumberFormatDigitOptions(lazyData, options, mnfdDefault, mxfdDefault) { - // We skip Step 1 because we set the properties on a lazyData object. - - // Step 2-3. - assert(IsObject(options), "SetNumberFormatDigitOptions"); - assert(typeof mnfdDefault === "number", "SetNumberFormatDigitOptions"); - assert(typeof mxfdDefault === "number", "SetNumberFormatDigitOptions"); - assert(mnfdDefault <= mxfdDefault, "SetNumberFormatDigitOptions"); - - // Steps 4-6. - const mnid = GetNumberOption(options, "minimumIntegerDigits", 1, 21, 1); - const mnfd = GetNumberOption(options, "minimumFractionDigits", 0, 20, mnfdDefault); - const mxfdActualDefault = std_Math_max(mnfd, mxfdDefault); - const mxfd = GetNumberOption(options, "maximumFractionDigits", mnfd, 20, mxfdActualDefault); - - // Steps 7-8. - let mnsd = options.minimumSignificantDigits; - let mxsd = options.maximumSignificantDigits; - - // Steps 9-11. - lazyData.minimumIntegerDigits = mnid; - lazyData.minimumFractionDigits = mnfd; - lazyData.maximumFractionDigits = mxfd; - - // Step 12. - if (mnsd !== undefined || mxsd !== undefined) { - mnsd = GetNumberOption(options, "minimumSignificantDigits", 1, 21, 1); - mxsd = GetNumberOption(options, "maximumSignificantDigits", mnsd, 21, 21); - lazyData.minimumSignificantDigits = mnsd; - lazyData.maximumSignificantDigits = mxsd; - } -} - /** * Initializes an object as a NumberFormat. @@ -1948,7 +1903,7 @@ function InitializeNumberFormat(numberFormat, locales, options) { // } // // Note that lazy data is only installed as a final step of initialization, - // so every NumberFormat lazy data object has *all* these properties, never a + // so every Collator lazy data object has *all* these properties, never a // subset of them. var lazyNumberFormatData = std_Object_create(null); @@ -1978,46 +1933,67 @@ function InitializeNumberFormat(numberFormat, locales, options) { opt.localeMatcher = matcher; // Compute formatting options. - // Step 14. - var style = GetOption(options, "style", "string", ["decimal", "percent", "currency"], "decimal"); - lazyNumberFormatData.style = style; + // Step 15. + var s = GetOption(options, "style", "string", ["decimal", "percent", "currency"], "decimal"); + lazyNumberFormatData.style = s; - // Steps 16-19. + // Steps 17-20. var c = GetOption(options, "currency", "string", undefined, undefined); if (c !== undefined && !IsWellFormedCurrencyCode(c)) ThrowRangeError(JSMSG_INVALID_CURRENCY_CODE, c); var cDigits; - if (style === "currency") { + if (s === "currency") { if (c === undefined) ThrowTypeError(JSMSG_UNDEFINED_CURRENCY); - // Steps 19.a-c. + // Steps 20.a-c. c = toASCIIUpperCase(c); lazyNumberFormatData.currency = c; cDigits = CurrencyDigits(c); } - // Step 20. + // Step 21. var cd = GetOption(options, "currencyDisplay", "string", ["code", "symbol", "name"], "symbol"); - if (style === "currency") + if (s === "currency") lazyNumberFormatData.currencyDisplay = cd; - // Steps 22-25. - var mnfdDefault, mxfdDefault; - if (style === "currency") { - mnfdDefault = cDigits; - mxfdDefault = cDigits; - } else { - mnfdDefault = 0; - mxfdDefault = style === "percent" ? 0 : 3; + // Step 23. + var mnid = GetNumberOption(options, "minimumIntegerDigits", 1, 21, 1); + lazyNumberFormatData.minimumIntegerDigits = mnid; + + // Steps 25-26. + var mnfdDefault = (s === "currency") ? cDigits : 0; + var mnfd = GetNumberOption(options, "minimumFractionDigits", 0, 20, mnfdDefault); + lazyNumberFormatData.minimumFractionDigits = mnfd; + + // Steps 28-29. + var mxfdDefault; + if (s === "currency") + mxfdDefault = std_Math_max(mnfd, cDigits); + else if (s === "percent") + mxfdDefault = std_Math_max(mnfd, 0); + else + mxfdDefault = std_Math_max(mnfd, 3); + var mxfd = GetNumberOption(options, "maximumFractionDigits", mnfd, 20, mxfdDefault); + lazyNumberFormatData.maximumFractionDigits = mxfd; + + // Steps 31-32. + var mnsd = options.minimumSignificantDigits; + var mxsd = options.maximumSignificantDigits; + + // Step 33. + if (mnsd !== undefined || mxsd !== undefined) { + mnsd = GetNumberOption(options, "minimumSignificantDigits", 1, 21, 1); + mxsd = GetNumberOption(options, "maximumSignificantDigits", mnsd, 21, 21); + lazyNumberFormatData.minimumSignificantDigits = mnsd; + lazyNumberFormatData.maximumSignificantDigits = mxsd; } - SetNumberFormatDigitOptions(lazyNumberFormatData, options, mnfdDefault, mxfdDefault); - // Steps 26. + // Step 34. var g = GetOption(options, "useGrouping", "boolean", undefined, true); lazyNumberFormatData.useGrouping = g; - // Steps 35-36. + // Step 43. // // We've done everything that must be done now: mark the lazy data as fully // computed and install it. @@ -2026,6 +2002,43 @@ function InitializeNumberFormat(numberFormat, locales, options) { /** + * Mapping from currency codes to the number of decimal digits used for them. + * Default is 2 digits. + * + * Spec: ISO 4217 Currency and Funds Code List. + * http://www.currency-iso.org/en/home/tables/table-a1.html + */ +var currencyDigits = { + BHD: 3, + BIF: 0, + BYR: 0, + CLF: 4, + CLP: 0, + DJF: 0, + GNF: 0, + IQD: 3, + ISK: 0, + JOD: 3, + JPY: 0, + KMF: 0, + KRW: 0, + KWD: 3, + LYD: 3, + OMR: 3, + PYG: 0, + RWF: 0, + TND: 3, + UGX: 0, + UYI: 0, + VND: 0, + VUV: 0, + XAF: 0, + XOF: 0, + XPF: 0 +}; + + +/** * Returns the number of decimal digits to be used for the given currency. * * Spec: ECMAScript Internationalization API Specification, 11.1.1. @@ -2106,7 +2119,7 @@ function numberFormatFormatToBind(value) { // Step 1.a.ii-iii. var x = ToNumber(value); - return intl_FormatNumber(this, x, /* formatToParts = */ false); + return intl_FormatNumber(this, x); } @@ -2133,22 +2146,6 @@ function Intl_NumberFormat_format_get() { // Step 2. return internals.boundFormat; } -_SetCanonicalName(Intl_NumberFormat_format_get, "get format"); - - -function Intl_NumberFormat_formatToParts(value) { - // Step 1. - var nf = this; - - // Steps 2-3. - getNumberFormatInternals(nf, "formatToParts"); - - // Step 4. - var x = ToNumber(value); - - // Step 5. - return intl_FormatNumber(nf, x, /* formatToParts = */ true); -} /** @@ -2290,6 +2287,26 @@ function getDateTimeFormatInternals(obj, methodName) { return internalProps; } +/** + * Components of date and time formats and their values. + * + * Spec: ECMAScript Internationalization API Specification, 12.1.1. + */ +var dateTimeComponentValues = { + weekday: ["narrow", "short", "long"], + era: ["narrow", "short", "long"], + year: ["2-digit", "numeric"], + month: ["2-digit", "numeric", "narrow", "short", "long"], + day: ["2-digit", "numeric"], + hour: ["2-digit", "numeric"], + minute: ["2-digit", "numeric"], + second: ["2-digit", "numeric"], + timeZoneName: ["short", "long"] +}; + + +var dateTimeComponents = std_Object_getOwnPropertyNames(dateTimeComponentValues); + /** * Initializes an object as a DateTimeFormat. @@ -2379,19 +2396,12 @@ function InitializeDateTimeFormat(dateTimeFormat, locales, options) { lazyDateTimeFormatData.formatOpt = formatOpt; // Step 19. - // 12.1, Table 4: Components of date and time formats. - formatOpt.weekday = GetOption(options, "weekday", "string", ["narrow", "short", "long"], - undefined); - formatOpt.era = GetOption(options, "era", "string", ["narrow", "short", "long"], undefined); - formatOpt.year = GetOption(options, "year", "string", ["2-digit", "numeric"], undefined); - formatOpt.month = GetOption(options, "month", "string", - ["2-digit", "numeric", "narrow", "short", "long"], undefined); - formatOpt.day = GetOption(options, "day", "string", ["2-digit", "numeric"], undefined); - formatOpt.hour = GetOption(options, "hour", "string", ["2-digit", "numeric"], undefined); - formatOpt.minute = GetOption(options, "minute", "string", ["2-digit", "numeric"], undefined); - formatOpt.second = GetOption(options, "second", "string", ["2-digit", "numeric"], undefined); - formatOpt.timeZoneName = GetOption(options, "timeZoneName", "string", ["short", "long"], - undefined); + var i, prop; + for (i = 0; i < dateTimeComponents.length; i++) { + prop = dateTimeComponents[i]; + var value = GetOption(options, prop, "string", dateTimeComponentValues[prop], undefined); + formatOpt[prop] = value; + } // Steps 20-21 provided by ICU - see comment after this function. @@ -2659,6 +2669,7 @@ function ToDateTimeOptions(options, required, defaults) { return options; } + /** * Compares the date and time components requested by options with the available * date and time formats in formats, and selects the best match according @@ -2844,7 +2855,6 @@ function Intl_DateTimeFormat_format_get() { // Step 2. return internals.boundFormat; } -_SetCanonicalName(Intl_DateTimeFormat_format_get, "get format"); function Intl_DateTimeFormat_formatToParts() { @@ -2980,232 +2990,6 @@ function resolveICUPattern(pattern, result) { } } -/********** Intl.PluralRules **********/ - -/** - * PluralRules internal properties. - * - * Spec: ECMAScript 402 API, PluralRules, 1.3.3. - */ -var pluralRulesInternalProperties = { - _availableLocales: null, - availableLocales: function() - { - var locales = this._availableLocales; - if (locales) - return locales; - - locales = intl_PluralRules_availableLocales(); - addSpecialMissingLanguageTags(locales); - return (this._availableLocales = locales); - } -}; - -/** - * Compute an internal properties object from |lazyPluralRulesData|. - */ -function resolvePluralRulesInternals(lazyPluralRulesData) { - assert(IsObject(lazyPluralRulesData), "lazy data not an object?"); - - var internalProps = std_Object_create(null); - - var requestedLocales = lazyPluralRulesData.requestedLocales; - - var PluralRules = pluralRulesInternalProperties; - - // Step 13. - const r = ResolveLocale(callFunction(PluralRules.availableLocales, PluralRules), - lazyPluralRulesData.requestedLocales, - lazyPluralRulesData.opt, - noRelevantExtensionKeys, undefined); - - // Step 14. - internalProps.locale = r.locale; - internalProps.type = lazyPluralRulesData.type; - - internalProps.pluralCategories = intl_GetPluralCategories( - internalProps.locale, - internalProps.type); - - internalProps.minimumIntegerDigits = lazyPluralRulesData.minimumIntegerDigits; - internalProps.minimumFractionDigits = lazyPluralRulesData.minimumFractionDigits; - internalProps.maximumFractionDigits = lazyPluralRulesData.maximumFractionDigits; - - if ("minimumSignificantDigits" in lazyPluralRulesData) { - assert("maximumSignificantDigits" in lazyPluralRulesData, "min/max sig digits mismatch"); - internalProps.minimumSignificantDigits = lazyPluralRulesData.minimumSignificantDigits; - internalProps.maximumSignificantDigits = lazyPluralRulesData.maximumSignificantDigits; - } - - return internalProps; -} - -/** - * Returns an object containing the PluralRules internal properties of |obj|, - * or throws a TypeError if |obj| isn't PluralRules-initialized. - */ -function getPluralRulesInternals(obj, methodName) { - var internals = getIntlObjectInternals(obj, "PluralRules", methodName); - assert(internals.type === "PluralRules", "bad type escaped getIntlObjectInternals"); - - var internalProps = maybeInternalProperties(internals); - if (internalProps) - return internalProps; - - internalProps = resolvePluralRulesInternals(internals.lazyData); - setInternalProperties(internals, internalProps); - return internalProps; -} - -/** - * Initializes an object as a PluralRules. - * - * This method is complicated a moderate bit by its implementing initialization - * as a *lazy* concept. Everything that must happen now, does -- but we defer - * all the work we can until the object is actually used as a PluralRules. - * This later work occurs in |resolvePluralRulesInternals|; steps not noted - * here occur there. - * - * Spec: ECMAScript 402 API, PluralRules, 1.1.1. - */ -function InitializePluralRules(pluralRules, locales, options) { - assert(IsObject(pluralRules), "InitializePluralRules"); - - // Step 1. - if (isInitializedIntlObject(pluralRules)) - ThrowTypeError(JSMSG_INTL_OBJECT_REINITED); - - let internals = initializeIntlObject(pluralRules); - - // Lazy PluralRules data has the following structure: - // - // { - // requestedLocales: List of locales, - // type: "cardinal" / "ordinal", - // - // opt: // opt object computer in InitializePluralRules - // { - // localeMatcher: "lookup" / "best fit", - // } - // - // minimumIntegerDigits: integer ∈ [1, 21], - // minimumFractionDigits: integer ∈ [0, 20], - // maximumFractionDigits: integer ∈ [0, 20], - // - // // optional - // minimumSignificantDigits: integer ∈ [1, 21], - // maximumSignificantDigits: integer ∈ [1, 21], - // } - // - // Note that lazy data is only installed as a final step of initialization, - // so every PluralRules lazy data object has *all* these properties, never a - // subset of them. - const lazyPluralRulesData = std_Object_create(null); - - // Step 3. - let requestedLocales = CanonicalizeLocaleList(locales); - lazyPluralRulesData.requestedLocales = requestedLocales; - - // Steps 4-5. - if (options === undefined) - options = {}; - else - options = ToObject(options); - - // Step 6. - const type = GetOption(options, "type", "string", ["cardinal", "ordinal"], "cardinal"); - lazyPluralRulesData.type = type; - - // Step 8. - let opt = new Record(); - lazyPluralRulesData.opt = opt; - - // Steps 9-10. - let matcher = GetOption(options, "localeMatcher", "string", ["lookup", "best fit"], "best fit"); - opt.localeMatcher = matcher; - - // Steps 11-12. - SetNumberFormatDigitOptions(lazyPluralRulesData, options, 0, 3); - - setLazyData(internals, "PluralRules", lazyPluralRulesData) -} - -/** - * Returns the subset of the given locale list for which this locale list has a - * matching (possibly fallback) locale. Locales appear in the same order in the - * returned list as in the input list. - * - * Spec: ECMAScript 402 API, PluralRules, 1.3.2. - */ -function Intl_PluralRules_supportedLocalesOf(locales /*, options*/) { - var options = arguments.length > 1 ? arguments[1] : undefined; - - // Step 1. - var availableLocales = callFunction(pluralRulesInternalProperties.availableLocales, - pluralRulesInternalProperties); - // Step 2. - let requestedLocales = CanonicalizeLocaleList(locales); - - // Step 3. - return SupportedLocales(availableLocales, requestedLocales, options); -} - -/** - * Returns a String value representing the plural category matching - * the number passed as value according to the - * effective locale and the formatting options of this PluralRules. - * - * Spec: ECMAScript 402 API, PluralRules, 1.4.3. - */ -function Intl_PluralRules_select(value) { - // Step 1. - let pluralRules = this; - // Step 2. - let internals = getPluralRulesInternals(pluralRules, "select"); - - // Steps 3-4. - let n = ToNumber(value); - - // Step 5. - return intl_SelectPluralRule(pluralRules, n); -} - -/** - * Returns the resolved options for a PluralRules object. - * - * Spec: ECMAScript 402 API, PluralRules, 1.4.4. - */ -function Intl_PluralRules_resolvedOptions() { - var internals = getPluralRulesInternals(this, "resolvedOptions"); - - var internalsPluralCategories = internals.pluralCategories; - var pluralCategories = []; - for (var i = 0; i < internalsPluralCategories.length; i++) - _DefineDataProperty(pluralCategories, i, internalsPluralCategories[i]); - - var result = { - locale: internals.locale, - type: internals.type, - pluralCategories, - minimumIntegerDigits: internals.minimumIntegerDigits, - minimumFractionDigits: internals.minimumFractionDigits, - maximumFractionDigits: internals.maximumFractionDigits, - }; - - var optionalProperties = [ - "minimumSignificantDigits", - "maximumSignificantDigits" - ]; - - for (var i = 0; i < optionalProperties.length; i++) { - var p = optionalProperties[i]; - if (callFunction(std_Object_hasOwnProperty, internals, p)) - _DefineDataProperty(result, p, internals[p]); - } - return result; -} - - function Intl_getCanonicalLocales(locales) { let codes = CanonicalizeLocaleList(locales); let result = []; @@ -3362,5 +3146,5 @@ function Intl_getDisplayNames(locales, options) { // 24. Return result. return result; -} +} diff --git a/js/src/builtin/IntlTimeZoneData.h b/js/src/builtin/IntlTimeZoneData.h index f92c583df..fa808c0b9 100644 --- a/js/src/builtin/IntlTimeZoneData.h +++ b/js/src/builtin/IntlTimeZoneData.h @@ -1,5 +1,5 @@ // Generated by make_intl_data.py. DO NOT EDIT. -// tzdata version = 2018c +// tzdata version = 2018e #ifndef builtin_IntlTimeZoneData_h #define builtin_IntlTimeZoneData_h diff --git a/js/src/builtin/Map.js b/js/src/builtin/Map.js index 580629a13..434cd6529 100644 --- a/js/src/builtin/Map.js +++ b/js/src/builtin/Map.js @@ -62,8 +62,8 @@ function MapIteratorNext() { var O = this; // Steps 2-3. - if (!IsObject(O) || !IsMapIterator(O)) - return callFunction(CallMapIteratorMethodIfWrapped, O, "MapIteratorNext"); + if (!IsObject(O) || (O = GuardToMapIterator(O)) === null) + return callFunction(CallMapIteratorMethodIfWrapped, this, "MapIteratorNext"); // Steps 4-5 (implemented in _GetNextMapEntryForIterator). // Steps 8-9 (omitted). @@ -82,7 +82,7 @@ function MapIteratorNext() { // Steps 10.b-c (omitted). // Step 6. - var itemKind = UnsafeGetInt32FromReservedSlot(this, ITERATOR_SLOT_ITEM_KIND); + var itemKind = UnsafeGetInt32FromReservedSlot(O, ITERATOR_SLOT_ITEM_KIND); var result; if (itemKind === ITEM_KIND_KEY) { diff --git a/js/src/builtin/Set.js b/js/src/builtin/Set.js index 9af6cf8d1..e2571e66a 100644 --- a/js/src/builtin/Set.js +++ b/js/src/builtin/Set.js @@ -64,8 +64,8 @@ function SetIteratorNext() { var O = this; // Steps 2-3. - if (!IsObject(O) || !IsSetIterator(O)) - return callFunction(CallSetIteratorMethodIfWrapped, O, "SetIteratorNext"); + if (!IsObject(O) || (O = GuardToSetIterator(O)) === null) + return callFunction(CallSetIteratorMethodIfWrapped, this, "SetIteratorNext"); // Steps 4-5 (implemented in _GetNextSetEntryForIterator). // Steps 8-9 (omitted). @@ -83,7 +83,7 @@ function SetIteratorNext() { // Steps 10.b-c (omitted). // Step 6. - var itemKind = UnsafeGetInt32FromReservedSlot(this, ITERATOR_SLOT_ITEM_KIND); + var itemKind = UnsafeGetInt32FromReservedSlot(O, ITERATOR_SLOT_ITEM_KIND); var result; if (itemKind === ITEM_KIND_VALUE) { diff --git a/js/src/builtin/String.js b/js/src/builtin/String.js index 4202d0de6..e5b2ad552 100644 --- a/js/src/builtin/String.js +++ b/js/src/builtin/String.js @@ -529,16 +529,17 @@ function String_iterator() { } function StringIteratorNext() { - if (!IsObject(this) || !IsStringIterator(this)) { + var obj; + if (!IsObject(this) || (obj = GuardToStringIterator(this)) === null) { return callFunction(CallStringIteratorMethodIfWrapped, this, "StringIteratorNext"); } - var S = UnsafeGetStringFromReservedSlot(this, ITERATOR_SLOT_TARGET); + var S = UnsafeGetStringFromReservedSlot(obj, ITERATOR_SLOT_TARGET); // We know that JSString::MAX_LENGTH <= INT32_MAX (and assert this in // SelfHostring.cpp) so our current index can never be anything other than // an Int32Value. - var index = UnsafeGetInt32FromReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX); + var index = UnsafeGetInt32FromReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX); var size = S.length; var result = { value: undefined, done: false }; @@ -556,7 +557,7 @@ function StringIteratorNext() { } } - UnsafeSetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX, index + charCount); + UnsafeSetReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX, index + charCount); result.value = callFunction(String_substring, S, index, index + charCount); return result; @@ -659,11 +660,7 @@ function String_static_localeCompare(str1, str2) { ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "String.localeCompare"); var locales = arguments.length > 2 ? arguments[2] : undefined; var options = arguments.length > 3 ? arguments[3] : undefined; -#if EXPOSE_INTL_API return callFunction(String_localeCompare, str1, str2, locales, options); -#else - return callFunction(std_String_localeCompare, str1, str2, locales, options); -#endif } // ES6 draft 2014-04-27 B.2.3.3 @@ -855,14 +852,12 @@ function String_static_toLocaleUpperCase(string) { return callFunction(std_String_toLocaleUpperCase, string); } -#if EXPOSE_INTL_API function String_static_normalize(string) { if (arguments.length < 1) ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.normalize'); var form = arguments.length > 1 ? arguments[1] : undefined; return callFunction(std_String_normalize, string, form); } -#endif function String_static_concat(string, arg1) { if (arguments.length < 1) diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index a14f9ba69..373b6c9ed 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -236,11 +236,7 @@ GetBuildConfiguration(JSContext* cx, unsigned argc, Value* vp) if (!JS_SetProperty(cx, info, "binary-data", value)) return false; -#ifdef EXPOSE_INTL_API value = BooleanValue(true); -#else - value = BooleanValue(false); -#endif if (!JS_SetProperty(cx, info, "intl-api", value)) return false; @@ -2092,7 +2088,7 @@ class CloneBufferObject : public NativeObject { Rooted<CloneBufferObject*> obj(cx, Create(cx)); if (!obj) return nullptr; - auto data = js::MakeUnique<JSStructuredCloneData>(); + auto data = js::MakeUnique<JSStructuredCloneData>(buffer->scope()); if (!data) { ReportOutOfMemory(cx); return nullptr; @@ -2145,8 +2141,11 @@ class CloneBufferObject : public NativeObject { return false; size_t nbytes = JS_GetStringLength(args[0].toString()); MOZ_ASSERT(nbytes % sizeof(uint64_t) == 0); - auto buf = js::MakeUnique<JSStructuredCloneData>(nbytes, nbytes, nbytes); - js_memcpy(buf->Start(), str, nbytes); + auto buf = js::MakeUnique<JSStructuredCloneData>(JS::StructuredCloneScope::DifferentProcess); + if (!buf->AppendBytes(str, nbytes)) { + ReportOutOfMemory(cx); + return false; + } JS_free(cx, str); obj->setData(buf.release()); @@ -2190,7 +2189,7 @@ class CloneBufferObject : public NativeObject { ReportOutOfMemory(cx); return false; } - auto iter = obj->data()->Iter(); + auto iter = obj->data()->Start(); obj->data()->ReadBytes(iter, buffer.get(), size); JSString* str = JS_NewStringCopyN(cx, buffer.get(), size); if (!str) @@ -2248,6 +2247,8 @@ ParseCloneScope(JSContext* cx, HandleString str) scope.emplace(JS::StructuredCloneScope::SameProcessDifferentThread); else if (strcmp(scopeStr.ptr(), "DifferentProcess") == 0) scope.emplace(JS::StructuredCloneScope::DifferentProcess); + else if (strcmp(scopeStr.ptr(), "DifferentProcessForIndexedDB") == 0) + scope.emplace(JS::StructuredCloneScope::DifferentProcessForIndexedDB); return scope; } @@ -4374,19 +4375,22 @@ JS_FN_HELP("rejectPromise", RejectPromise, 2, 0, " clone buffer object. 'policy' may be an options hash. Valid keys:\n" " 'SharedArrayBuffer' - either 'allow' (the default) or 'deny'\n" " to specify whether SharedArrayBuffers may be serialized.\n" -"\n" -" 'scope' - SameProcessSameThread, SameProcessDifferentThread, or\n" -" DifferentProcess. Determines how some values will be serialized.\n" -" Clone buffers may only be deserialized with a compatible scope."), +" 'scope' - SameProcessSameThread, SameProcessDifferentThread,\n" +" DifferentProcess, or DifferentProcessForIndexedDB. Determines how some\n" +" values will be serialized. Clone buffers may only be deserialized with a\n" +" compatible scope. NOTE - For DifferentProcess/DifferentProcessForIndexedDB,\n" +" must also set SharedArrayBuffer:'deny' if data contains any shared memory\n" +" object."), JS_FN_HELP("deserialize", Deserialize, 1, 0, "deserialize(clonebuffer[, opts])", " Deserialize data generated by serialize. 'opts' is an options hash with one\n" " recognized key 'scope', which limits the clone buffers that are considered\n" " valid. Allowed values: 'SameProcessSameThread', 'SameProcessDifferentThread',\n" -" and 'DifferentProcess'. So for example, a DifferentProcess clone buffer\n" -" may be deserialized in any scope, but a SameProcessSameThread clone buffer\n" -" cannot be deserialized in a DifferentProcess scope."), +" 'DifferentProcess', and 'DifferentProcessForIndexedDB'. So for example, a\n" +" DifferentProcessForIndexedDB clone buffer may be deserialized in any scope, but\n" +" a SameProcessSameThread clone buffer cannot be deserialized in a\n" +" DifferentProcess scope."), JS_FN_HELP("detachArrayBuffer", DetachArrayBuffer, 1, 0, "detachArrayBuffer(buffer)", diff --git a/js/src/builtin/TypedArray.js b/js/src/builtin/TypedArray.js index a2205dc92..a1934051d 100644 --- a/js/src/builtin/TypedArray.js +++ b/js/src/builtin/TypedArray.js @@ -1232,11 +1232,7 @@ function TypedArrayToLocaleString(locales = undefined, options = undefined) { // Steps 6-7. // Omit the 'if' clause in step 6, since typed arrays can't have undefined // or null elements. -#if EXPOSE_INTL_API var R = ToString(callContentFunction(firstElement.toLocaleString, firstElement, locales, options)); -#else - var R = ToString(callContentFunction(firstElement.toLocaleString, firstElement)); -#endif // Step 3 (reordered). // We don't (yet?) implement locale-dependent separators. @@ -1258,11 +1254,7 @@ function TypedArrayToLocaleString(locales = undefined, options = undefined) { // the error message. So despite bug 1079853, we can skip step 9.c. // Step 9.d. -#if EXPOSE_INTL_API R = ToString(callContentFunction(nextElement.toLocaleString, nextElement, locales, options)); -#else - R = ToString(callContentFunction(nextElement.toLocaleString, nextElement)); -#endif // Step 9.e. R = S + R; |