michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /*global intl_Collator: false, */ michael@0: michael@0: /* ES6 Draft September 5, 2013 21.1.3.3 */ michael@0: function String_codePointAt(pos) { michael@0: // Steps 1-3. michael@0: CheckObjectCoercible(this); michael@0: var S = ToString(this); michael@0: michael@0: // Steps 4-5. michael@0: var position = ToInteger(pos); michael@0: michael@0: // Step 6. michael@0: var size = S.length; michael@0: michael@0: // Step 7. michael@0: if (position < 0 || position >= size) michael@0: return undefined; michael@0: michael@0: // Steps 8-9. michael@0: var first = callFunction(std_String_charCodeAt, S, position); michael@0: if (first < 0xD800 || first > 0xDBFF || position + 1 === size) michael@0: return first; michael@0: michael@0: // Steps 10-11. michael@0: var second = callFunction(std_String_charCodeAt, S, position + 1); michael@0: if (second < 0xDC00 || second > 0xDFFF) michael@0: return first; michael@0: michael@0: // Step 12. michael@0: return (first - 0xD800) * 0x400 + (second - 0xDC00) + 0x10000; michael@0: } michael@0: michael@0: var collatorCache = new Record(); michael@0: michael@0: /* ES6 20121122 draft 15.5.4.21. */ michael@0: function String_repeat(count) { michael@0: // Steps 1-3. michael@0: CheckObjectCoercible(this); michael@0: var S = ToString(this); michael@0: michael@0: // Steps 4-5. michael@0: var n = ToInteger(count); michael@0: michael@0: // Steps 6-7. michael@0: if (n < 0) michael@0: ThrowError(JSMSG_NEGATIVE_REPETITION_COUNT); // a RangeError michael@0: michael@0: if (!(n * S.length < (1 << 28))) michael@0: ThrowError(JSMSG_RESULTING_STRING_TOO_LARGE); // a RangeError michael@0: michael@0: // Communicate |n|'s possible range to the compiler. michael@0: n = n & ((1 << 28) - 1); michael@0: michael@0: // Steps 8-9. michael@0: var T = ""; michael@0: for (;;) { michael@0: if (n & 1) michael@0: T += S; michael@0: n >>= 1; michael@0: if (n) michael@0: S += S; michael@0: else michael@0: break; michael@0: } michael@0: return T; michael@0: } michael@0: michael@0: #define STRING_ITERATOR_SLOT_ITERATED_OBJECT 0 michael@0: #define STRING_ITERATOR_SLOT_NEXT_INDEX 1 michael@0: michael@0: // ES6 draft specification, section 21.1.3.27, version 2013-09-27. michael@0: function String_iterator() { michael@0: CheckObjectCoercible(this); michael@0: var S = ToString(this); michael@0: var iterator = NewStringIterator(); michael@0: UnsafeSetReservedSlot(iterator, STRING_ITERATOR_SLOT_ITERATED_OBJECT, S); michael@0: UnsafeSetReservedSlot(iterator, STRING_ITERATOR_SLOT_NEXT_INDEX, 0); michael@0: return iterator; michael@0: } michael@0: michael@0: function StringIteratorIdentity() { michael@0: return this; michael@0: } michael@0: michael@0: function StringIteratorNext() { michael@0: // FIXME: Cross-compartment wrapper StringIterator objects should pass this test. Bug 924059. michael@0: if (!IsObject(this) || !IsStringIterator(this)) michael@0: ThrowError(JSMSG_INCOMPATIBLE_METHOD, "StringIterator", "next", ToString(this)); michael@0: michael@0: var S = UnsafeGetReservedSlot(this, STRING_ITERATOR_SLOT_ITERATED_OBJECT); michael@0: var index = UnsafeGetReservedSlot(this, STRING_ITERATOR_SLOT_NEXT_INDEX); michael@0: var size = S.length; michael@0: michael@0: if (index >= size) { michael@0: return { value: undefined, done: true }; michael@0: } michael@0: michael@0: var charCount = 1; michael@0: var first = callFunction(std_String_charCodeAt, S, index); michael@0: if (first >= 0xD800 && first <= 0xDBFF && index + 1 < size) { michael@0: var second = callFunction(std_String_charCodeAt, S, index + 1); michael@0: if (second >= 0xDC00 && second <= 0xDFFF) { michael@0: charCount = 2; michael@0: } michael@0: } michael@0: michael@0: UnsafeSetReservedSlot(this, STRING_ITERATOR_SLOT_NEXT_INDEX, index + charCount); michael@0: var value = callFunction(std_String_substring, S, index, index + charCount); michael@0: michael@0: return { value: value, done: false }; michael@0: } michael@0: michael@0: /** michael@0: * Compare this String against that String, using the locale and collation michael@0: * options provided. michael@0: * michael@0: * Spec: ECMAScript Internationalization API Specification, 13.1.1. michael@0: */ michael@0: function String_localeCompare(that) { michael@0: // Steps 1-3. michael@0: CheckObjectCoercible(this); michael@0: var S = ToString(this); michael@0: var That = ToString(that); michael@0: michael@0: // Steps 4-5. michael@0: var locales = arguments.length > 1 ? arguments[1] : undefined; michael@0: var options = arguments.length > 2 ? arguments[2] : undefined; michael@0: michael@0: // Step 6. michael@0: var collator; michael@0: if (locales === undefined && options === undefined) { michael@0: // This cache only optimizes for the old ES5 localeCompare without michael@0: // locales and options. michael@0: if (collatorCache.collator === undefined) michael@0: collatorCache.collator = intl_Collator(locales, options); michael@0: collator = collatorCache.collator; michael@0: } else { michael@0: collator = intl_Collator(locales, options); michael@0: } michael@0: michael@0: // Step 7. michael@0: return intl_CompareStrings(collator, S, That); michael@0: } michael@0: michael@0: /* ES6 Draft September 5, 2013 21.1.2.2 */ michael@0: function String_static_fromCodePoint() { michael@0: // Step 1. is not relevant michael@0: // Step 2. michael@0: var length = arguments.length; michael@0: michael@0: // Step 3. michael@0: var elements = new List(); michael@0: michael@0: // Step 4-5., 5g. michael@0: for (var nextIndex = 0; nextIndex < length; nextIndex++) { michael@0: // Step 5a. michael@0: var next = arguments[nextIndex]; michael@0: // Step 5b-c. michael@0: var nextCP = ToNumber(next); michael@0: michael@0: // Step 5d. michael@0: if (nextCP !== ToInteger(nextCP) || std_isNaN(nextCP)) michael@0: ThrowError(JSMSG_NOT_A_CODEPOINT, ToString(nextCP)); michael@0: michael@0: // Step 5e. michael@0: if (nextCP < 0 || nextCP > 0x10FFFF) michael@0: ThrowError(JSMSG_NOT_A_CODEPOINT, ToString(nextCP)); michael@0: michael@0: // Step 5f. michael@0: // Inlined UTF-16 Encoding michael@0: if (nextCP <= 0xFFFF) { michael@0: elements.push(nextCP); michael@0: continue; michael@0: } michael@0: michael@0: elements.push((((nextCP - 0x10000) / 0x400) | 0) + 0xD800); michael@0: elements.push((nextCP - 0x10000) % 0x400 + 0xDC00); michael@0: } michael@0: michael@0: // Step 6. michael@0: return callFunction(std_Function_apply, std_String_fromCharCode, null, elements); michael@0: } michael@0: michael@0: /** michael@0: * Compare String str1 against String str2, using the locale and collation michael@0: * options provided. michael@0: * michael@0: * Mozilla proprietary. michael@0: * Spec: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String#String_generic_methods michael@0: */ michael@0: function String_static_localeCompare(str1, str2) { michael@0: if (arguments.length < 1) michael@0: ThrowError(JSMSG_MISSING_FUN_ARG, 0, "String.localeCompare"); michael@0: var locales = arguments.length > 2 ? arguments[2] : undefined; michael@0: var options = arguments.length > 3 ? arguments[3] : undefined; michael@0: return callFunction(String_localeCompare, str1, str2, locales, options); michael@0: } michael@0: