/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /** * Intl.Segmenter internal properties. */ function segmenterLocaleData() { // Segmenter doesn't support any extension keys. return {}; } var segmenterInternalProperties = { localeData: segmenterLocaleData, relevantExtensionKeys: [], }; /** * Intl.Segmenter ( [ locales [ , options ] ] ) * * Compute an internal properties object from |lazySegmenterData|. */ function resolveSegmenterInternals(lazySegmenterData) { assert(IsObject(lazySegmenterData), "lazy data not an object?"); var internalProps = std_Object_create(null); var Segmenter = segmenterInternalProperties; // Compute effective locale. // Step 9. var localeData = Segmenter.localeData; // Step 10. var r = ResolveLocale( "Segmenter", lazySegmenterData.requestedLocales, lazySegmenterData.opt, Segmenter.relevantExtensionKeys, localeData ); // Step 11. internalProps.locale = r.locale; // Step 13. internalProps.granularity = lazySegmenterData.granularity; // The caller is responsible for associating |internalProps| with the right // object using |setInternalProperties|. return internalProps; } /** * Returns an object containing the Segmenter internal properties of |obj|. */ function getSegmenterInternals(obj) { assert(IsObject(obj), "getSegmenterInternals called with non-object"); assert( intl_GuardToSegmenter(obj) !== null, "getSegmenterInternals called with non-Segmenter" ); var internals = getIntlObjectInternals(obj); assert( internals.type === "Segmenter", "bad type escaped getIntlObjectInternals" ); // If internal properties have already been computed, use them. var internalProps = maybeInternalProperties(internals); if (internalProps) { return internalProps; } // Otherwise it's time to fully create them. internalProps = resolveSegmenterInternals(internals.lazyData); setInternalProperties(internals, internalProps); return internalProps; } /** * Intl.Segmenter ( [ locales [ , options ] ] ) * * Initializes an object as a Segmenter. * * 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 Segmenter. * This later work occurs in |resolveSegmenterInternals|; steps not noted here * occur there. */ function InitializeSegmenter(segmenter, locales, options) { assert(IsObject(segmenter), "InitializeSegmenter called with non-object"); assert( intl_GuardToSegmenter(segmenter) !== null, "InitializeSegmenter called with non-Segmenter" ); // Lazy Segmenter data has the following structure: // // { // requestedLocales: List of locales, // // opt: // opt object computed in InitializeSegmenter // { // localeMatcher: "lookup" / "best fit", // } // // granularity: "grapheme" / "word" / "sentence", // } // // Note that lazy data is only installed as a final step of initialization, // so every Segmenter lazy data object has *all* these properties, never a // subset of them. var lazySegmenterData = std_Object_create(null); // Step 4. var requestedLocales = CanonicalizeLocaleList(locales); lazySegmenterData.requestedLocales = requestedLocales; // Step 5. if (options === undefined) { options = std_Object_create(null); } else if (!IsObject(options)) { ThrowTypeError( JSMSG_OBJECT_REQUIRED, options === null ? "null" : typeof options ); } // Step 6. var opt = new_Record(); lazySegmenterData.opt = opt; // Steps 7-8. var matcher = GetOption( options, "localeMatcher", "string", ["lookup", "best fit"], "best fit" ); opt.localeMatcher = matcher; // Steps 12-13. var granularity = GetOption( options, "granularity", "string", ["grapheme", "word", "sentence"], "grapheme" ); lazySegmenterData.granularity = granularity; // We've done everything that must be done now: mark the lazy data as fully // computed and install it. initializeIntlObject(segmenter, "Segmenter", lazySegmenterData); } /** * Intl.Segmenter.supportedLocalesOf ( locales [, options ]) * * 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. */ function Intl_Segmenter_supportedLocalesOf(locales /*, options*/) { var options = ArgumentsLength() > 1 ? GetArgument(1) : undefined; // Step 1. var availableLocales = "Segmenter"; // Step 2. var requestedLocales = CanonicalizeLocaleList(locales); // Step 3. return SupportedLocales(availableLocales, requestedLocales, options); } /** * Intl.Segmenter.prototype.segment ( string ) * * Create a new Segments object. */ function Intl_Segmenter_segment(value) { // Step 1. var segmenter = this; // Step 2. if ( !IsObject(segmenter) || (segmenter = intl_GuardToSegmenter(segmenter)) === null ) { return callFunction( intl_CallSegmenterMethodIfWrapped, this, value, "Intl_Segmenter_segment" ); } // Ensure the Segmenter internals are resolved. getSegmenterInternals(segmenter); // Step 3. var string = ToString(value); // Step 4. return intl_CreateSegmentsObject(segmenter, string); } /** * Intl.Segmenter.prototype.resolvedOptions () * * Returns the resolved options for a Segmenter object. */ function Intl_Segmenter_resolvedOptions() { // Step 1. var segmenter = this; // Step 2. if ( !IsObject(segmenter) || (segmenter = intl_GuardToSegmenter(segmenter)) === null ) { return callFunction( intl_CallSegmenterMethodIfWrapped, this, "Intl_Segmenter_resolvedOptions" ); } var internals = getSegmenterInternals(segmenter); // Steps 3-4. var options = { locale: internals.locale, granularity: internals.granularity, }; // Step 5. return options; } /** * CreateSegmentDataObject ( segmenter, string, startIndex, endIndex ) */ function CreateSegmentDataObject(string, boundaries) { assert(typeof string === "string", "CreateSegmentDataObject"); assert( IsPackedArray(boundaries) && boundaries.length === 3, "CreateSegmentDataObject" ); var startIndex = boundaries[0]; assert( typeof startIndex === "number" && (startIndex | 0) === startIndex, "startIndex is an int32-value" ); var endIndex = boundaries[1]; assert( typeof endIndex === "number" && (endIndex | 0) === endIndex, "endIndex is an int32-value" ); // In our implementation |granularity| is encoded in |isWordLike|. var isWordLike = boundaries[2]; assert( typeof isWordLike === "boolean" || isWordLike === undefined, "isWordLike is either a boolean or undefined" ); // Step 1 (Not applicable). // Step 2. assert(startIndex >= 0, "startIndex is a positive number"); // Step 3. assert( endIndex <= string.length, "endIndex is less-than-equals the string length" ); // Step 4. assert(startIndex < endIndex, "startIndex is strictly less than endIndex"); // Step 6. var segment = Substring(string, startIndex, endIndex - startIndex); // Steps 5, 7-12. if (isWordLike === undefined) { return { segment, index: startIndex, input: string, }; } return { segment, index: startIndex, input: string, isWordLike, }; } /** * %Segments.prototype%.containing ( index ) * * Return a Segment Data object describing the segment at the given index. If * the index exceeds the string bounds, undefined is returned. */ function Intl_Segments_containing(index) { // Step 1. var segments = this; // Step 2. if ( !IsObject(segments) || (segments = intl_GuardToSegments(segments)) === null ) { return callFunction( intl_CallSegmentsMethodIfWrapped, this, index, "Intl_Segments_containing" ); } // Step 3 (not applicable). // Step 4. var string = UnsafeGetStringFromReservedSlot( segments, INTL_SEGMENTS_STRING_SLOT ); // Step 5. var len = string.length; // Step 6. var n = ToInteger(index); // Step 7. if (n < 0 || n >= len) { return undefined; } // Steps 8-9. var boundaries = intl_FindSegmentBoundaries(segments, n | 0); // Step 10. return CreateSegmentDataObject(string, boundaries); } /** * %Segments.prototype% [ @@iterator ] () * * Create a new Segment Iterator object. */ function Intl_Segments_iterator() { // Step 1. var segments = this; // Step 2. if ( !IsObject(segments) || (segments = intl_GuardToSegments(segments)) === null ) { return callFunction( intl_CallSegmentsMethodIfWrapped, this, "Intl_Segments_iterator" ); } // Steps 3-5. return intl_CreateSegmentIterator(segments); } /** * %SegmentIterator.prototype%.next () * * Advance the Segment iterator to the next segment within the string. */ function Intl_SegmentIterator_next() { // Step 1. var iterator = this; // Step 2. if ( !IsObject(iterator) || (iterator = intl_GuardToSegmentIterator(iterator)) === null) { return callFunction( intl_CallSegmentIteratorMethodIfWrapped, this, "Intl_SegmentIterator_next" ); } // Step 3 (Not applicable). // Step 4. var string = UnsafeGetStringFromReservedSlot( iterator, INTL_SEGMENT_ITERATOR_STRING_SLOT ); // Step 5. var index = UnsafeGetInt32FromReservedSlot( iterator, INTL_SEGMENT_ITERATOR_INDEX_SLOT ); var result = { value: undefined, done: false }; // Step 7. if (index === string.length) { result.done = true; return result; } // Steps 6, 8. var boundaries = intl_FindNextSegmentBoundaries(iterator); // Step 9. result.value = CreateSegmentDataObject(string, boundaries); // Step 10. return result; }