From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- js/src/builtin/intl/Segmenter.js | 434 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 434 insertions(+) create mode 100644 js/src/builtin/intl/Segmenter.js (limited to 'js/src/builtin/intl/Segmenter.js') diff --git a/js/src/builtin/intl/Segmenter.js b/js/src/builtin/intl/Segmenter.js new file mode 100644 index 0000000000..7c46091b56 --- /dev/null +++ b/js/src/builtin/intl/Segmenter.js @@ -0,0 +1,434 @@ +/* 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; +} -- cgit v1.2.3