Issue #2046 - Move Intl.Collator self-hosted code to a new builtin/intl/Collator.js file

This commit is contained in:
Martok 2023-02-17 00:01:59 +01:00 committed by roytam1
commit 45720521cf
3 changed files with 356 additions and 353 deletions

View file

@ -1406,356 +1406,3 @@ function getInternals(obj)
return internalProps;
}
/********** Intl.Collator **********/
/**
* Mapping from Unicode extension keys for collation to options properties,
* their types and permissible values.
*
* Spec: ECMAScript Internationalization API Specification, 10.1.1.
*/
var collatorKeyMappings = {
kn: {property: "numeric", type: "boolean"},
kf: {property: "caseFirst", type: "string", values: ["upper", "lower", "false"]}
};
/**
* Compute an internal properties object from |lazyCollatorData|.
*/
function resolveCollatorInternals(lazyCollatorData)
{
assert(IsObject(lazyCollatorData), "lazy data not an object?");
var internalProps = std_Object_create(null);
// Step 7.
internalProps.usage = lazyCollatorData.usage;
// Step 8.
var Collator = collatorInternalProperties;
// Step 9.
var collatorIsSorting = lazyCollatorData.usage === "sort";
var localeData = collatorIsSorting
? Collator.sortLocaleData
: Collator.searchLocaleData;
// Compute effective locale.
// Step 14.
var relevantExtensionKeys = Collator.relevantExtensionKeys;
// Step 15.
var r = ResolveLocale(callFunction(Collator.availableLocales, Collator),
lazyCollatorData.requestedLocales,
lazyCollatorData.opt,
relevantExtensionKeys,
localeData);
// Step 16.
internalProps.locale = r.locale;
// Steps 17-19.
var key, property, value, mapping;
var i = 0, len = relevantExtensionKeys.length;
while (i < len) {
// Step 19.a.
key = relevantExtensionKeys[i];
if (key === "co") {
// Step 19.b.
property = "collation";
value = r.co === null ? "default" : r.co;
} else {
// Step 19.c.
mapping = collatorKeyMappings[key];
property = mapping.property;
value = r[key];
if (mapping.type === "boolean")
value = value === "true";
}
// Step 19.d.
internalProps[property] = value;
// Step 19.e.
i++;
}
// Compute remaining collation options.
// Steps 21-22.
var s = lazyCollatorData.rawSensitivity;
if (s === undefined) {
if (collatorIsSorting) {
// Step 21.a.
s = "variant";
} else {
// Step 21.b.
var dataLocale = r.dataLocale;
var dataLocaleData = localeData(dataLocale);
s = dataLocaleData.sensitivity;
}
}
internalProps.sensitivity = s;
// Step 24.
internalProps.ignorePunctuation = lazyCollatorData.ignorePunctuation;
// Step 25.
internalProps.boundFormat = undefined;
// The caller is responsible for associating |internalProps| with the right
// object using |setInternalProperties|.
return internalProps;
}
/**
* Returns an object containing the Collator internal properties of |obj|, or
* throws a TypeError if |obj| isn't Collator-initialized.
*/
function getCollatorInternals(obj, methodName) {
var internals = getIntlObjectInternals(obj, "Collator", methodName);
assert(internals.type === "Collator", "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 = resolveCollatorInternals(internals.lazyData);
setInternalProperties(internals, internalProps);
return internalProps;
}
/**
* Initializes an object as a Collator.
*
* 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 Collator. This
* later work occurs in |resolveCollatorInternals|; steps not noted here occur
* there.
*
* Spec: ECMAScript Internationalization API Specification, 10.1.1.
*/
function InitializeCollator(collator, locales, options) {
assert(IsObject(collator), "InitializeCollator");
// Step 1.
if (isInitializedIntlObject(collator))
ThrowTypeError(JSMSG_INTL_OBJECT_REINITED);
// Step 2.
var internals = initializeIntlObject(collator);
// Lazy Collator data has the following structure:
//
// {
// requestedLocales: List of locales,
// usage: "sort" / "search",
// opt: // opt object computed in InitializeCollator
// {
// localeMatcher: "lookup" / "best fit",
// kn: true / false / undefined,
// kf: "upper" / "lower" / "false" / undefined
// }
// rawSensitivity: "base" / "accent" / "case" / "variant" / undefined,
// ignorePunctuation: true / false
// }
//
// Note that lazy data is only installed as a final step of initialization,
// so every Collator lazy data object has *all* these properties, never a
// subset of them.
var lazyCollatorData = std_Object_create(null);
// Step 3.
var requestedLocales = CanonicalizeLocaleList(locales);
lazyCollatorData.requestedLocales = requestedLocales;
// Steps 4-5.
//
// If we ever need more speed here at startup, we should try to detect the
// case where |options === undefined| and Object.prototype hasn't been
// mucked with. (|options| is fully consumed in this method, so it's not a
// concern that Object.prototype might be touched between now and when
// |resolveCollatorInternals| is called.) For now, just keep it simple.
if (options === undefined)
options = {};
else
options = ToObject(options);
// Compute options that impact interpretation of locale.
// Step 6.
var u = GetOption(options, "usage", "string", ["sort", "search"], "sort");
lazyCollatorData.usage = u;
// Step 10.
var opt = new Record();
lazyCollatorData.opt = opt;
// Steps 11-12.
var matcher = GetOption(options, "localeMatcher", "string", ["lookup", "best fit"], "best fit");
opt.localeMatcher = matcher;
// Step 13, unrolled.
var numericValue = GetOption(options, "numeric", "boolean", undefined, undefined);
if (numericValue !== undefined)
numericValue = numericValue ? 'true' : 'false';
opt.kn = numericValue;
var caseFirstValue = GetOption(options, "caseFirst", "string", ["upper", "lower", "false"], undefined);
opt.kf = caseFirstValue;
// Compute remaining collation options.
// Step 20.
var s = GetOption(options, "sensitivity", "string",
["base", "accent", "case", "variant"], undefined);
lazyCollatorData.rawSensitivity = s;
// Step 23.
var ip = GetOption(options, "ignorePunctuation", "boolean", undefined, false);
lazyCollatorData.ignorePunctuation = ip;
// Step 26.
//
// We've done everything that must be done now: mark the lazy data as fully
// computed and install it.
setLazyData(internals, "Collator", lazyCollatorData);
}
/**
* 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 Internationalization API Specification, 10.2.2.
*/
function Intl_Collator_supportedLocalesOf(locales /*, options*/) {
var options = arguments.length > 1 ? arguments[1] : undefined;
var availableLocales = callFunction(collatorInternalProperties.availableLocales,
collatorInternalProperties);
var requestedLocales = CanonicalizeLocaleList(locales);
return SupportedLocales(availableLocales, requestedLocales, options);
}
/**
* Collator internal properties.
*
* Spec: ECMAScript Internationalization API Specification, 9.1 and 10.2.3.
*/
var collatorInternalProperties = {
sortLocaleData: collatorSortLocaleData,
searchLocaleData: collatorSearchLocaleData,
_availableLocales: null,
availableLocales: function()
{
var locales = this._availableLocales;
if (locales)
return locales;
locales = intl_Collator_availableLocales();
addSpecialMissingLanguageTags(locales);
return (this._availableLocales = locales);
},
relevantExtensionKeys: ["co", "kn"]
};
function collatorSortLocaleData(locale) {
var collations = intl_availableCollations(locale);
callFunction(std_Array_unshift, collations, null);
return {
co: collations,
kn: ["false", "true"]
};
}
function collatorSearchLocaleData(locale) {
return {
co: [null],
kn: ["false", "true"],
// In theory the default sensitivity is locale dependent;
// in reality the CLDR/ICU default strength is always tertiary.
sensitivity: "variant"
};
}
/**
* Function to be bound and returned by Intl.Collator.prototype.format.
*
* Spec: ECMAScript Internationalization API Specification, 12.3.2.
*/
function collatorCompareToBind(x, y) {
// Steps 1.a.i-ii implemented by ECMAScript declaration binding instantiation,
// ES5.1 10.5, step 4.d.ii.
// Step 1.a.iii-v.
var X = ToString(x);
var Y = ToString(y);
return intl_CompareStrings(this, X, Y);
}
/**
* Returns a function bound to this Collator that compares x (converted to a
* String value) and y (converted to a String value),
* and returns a number less than 0 if x < y, 0 if x = y, or a number greater
* than 0 if x > y according to the sort order for the locale and collation
* options of this Collator object.
*
* Spec: ECMAScript Internationalization API Specification, 10.3.2.
*/
function Intl_Collator_compare_get() {
// Check "this Collator object" per introduction of section 10.3.
var internals = getCollatorInternals(this, "compare");
// Step 1.
if (internals.boundCompare === undefined) {
// Step 1.a.
var F = collatorCompareToBind;
// Step 1.b-d.
var bc = callFunction(FunctionBind, F, this);
internals.boundCompare = bc;
}
// Step 2.
return internals.boundCompare;
}
/**
* Returns the resolved options for a Collator object.
*
* Spec: ECMAScript Internationalization API Specification, 10.3.3 and 10.4.
*/
function Intl_Collator_resolvedOptions() {
// Check "this Collator object" per introduction of section 10.3.
var internals = getCollatorInternals(this, "resolvedOptions");
var result = {
locale: internals.locale,
usage: internals.usage,
sensitivity: internals.sensitivity,
ignorePunctuation: internals.ignorePunctuation
};
var relevantExtensionKeys = collatorInternalProperties.relevantExtensionKeys;
for (var i = 0; i < relevantExtensionKeys.length; i++) {
var key = relevantExtensionKeys[i];
var property = (key === "co") ? "collation" : collatorKeyMappings[key].property;
_DefineDataProperty(result, property, internals[property]);
}
return result;
}

View file

@ -0,0 +1,355 @@
/* 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.Collator **********/
/**
* Mapping from Unicode extension keys for collation to options properties,
* their types and permissible values.
*
* Spec: ECMAScript Internationalization API Specification, 10.1.1.
*/
var collatorKeyMappings = {
kn: {property: "numeric", type: "boolean"},
kf: {property: "caseFirst", type: "string", values: ["upper", "lower", "false"]}
};
/**
* Compute an internal properties object from |lazyCollatorData|.
*/
function resolveCollatorInternals(lazyCollatorData)
{
assert(IsObject(lazyCollatorData), "lazy data not an object?");
var internalProps = std_Object_create(null);
// Step 7.
internalProps.usage = lazyCollatorData.usage;
// Step 8.
var Collator = collatorInternalProperties;
// Step 9.
var collatorIsSorting = lazyCollatorData.usage === "sort";
var localeData = collatorIsSorting
? Collator.sortLocaleData
: Collator.searchLocaleData;
// Compute effective locale.
// Step 14.
var relevantExtensionKeys = Collator.relevantExtensionKeys;
// Step 15.
var r = ResolveLocale(callFunction(Collator.availableLocales, Collator),
lazyCollatorData.requestedLocales,
lazyCollatorData.opt,
relevantExtensionKeys,
localeData);
// Step 16.
internalProps.locale = r.locale;
// Steps 17-19.
var key, property, value, mapping;
var i = 0, len = relevantExtensionKeys.length;
while (i < len) {
// Step 19.a.
key = relevantExtensionKeys[i];
if (key === "co") {
// Step 19.b.
property = "collation";
value = r.co === null ? "default" : r.co;
} else {
// Step 19.c.
mapping = collatorKeyMappings[key];
property = mapping.property;
value = r[key];
if (mapping.type === "boolean")
value = value === "true";
}
// Step 19.d.
internalProps[property] = value;
// Step 19.e.
i++;
}
// Compute remaining collation options.
// Steps 21-22.
var s = lazyCollatorData.rawSensitivity;
if (s === undefined) {
if (collatorIsSorting) {
// Step 21.a.
s = "variant";
} else {
// Step 21.b.
var dataLocale = r.dataLocale;
var dataLocaleData = localeData(dataLocale);
s = dataLocaleData.sensitivity;
}
}
internalProps.sensitivity = s;
// Step 24.
internalProps.ignorePunctuation = lazyCollatorData.ignorePunctuation;
// Step 25.
internalProps.boundFormat = undefined;
// The caller is responsible for associating |internalProps| with the right
// object using |setInternalProperties|.
return internalProps;
}
/**
* Returns an object containing the Collator internal properties of |obj|, or
* throws a TypeError if |obj| isn't Collator-initialized.
*/
function getCollatorInternals(obj, methodName) {
var internals = getIntlObjectInternals(obj, "Collator", methodName);
assert(internals.type === "Collator", "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 = resolveCollatorInternals(internals.lazyData);
setInternalProperties(internals, internalProps);
return internalProps;
}
/**
* Initializes an object as a Collator.
*
* 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 Collator. This
* later work occurs in |resolveCollatorInternals|; steps not noted here occur
* there.
*
* Spec: ECMAScript Internationalization API Specification, 10.1.1.
*/
function InitializeCollator(collator, locales, options) {
assert(IsObject(collator), "InitializeCollator");
// Step 1.
if (isInitializedIntlObject(collator))
ThrowTypeError(JSMSG_INTL_OBJECT_REINITED);
// Step 2.
var internals = initializeIntlObject(collator);
// Lazy Collator data has the following structure:
//
// {
// requestedLocales: List of locales,
// usage: "sort" / "search",
// opt: // opt object computed in InitializeCollator
// {
// localeMatcher: "lookup" / "best fit",
// kn: true / false / undefined,
// kf: "upper" / "lower" / "false" / undefined
// }
// rawSensitivity: "base" / "accent" / "case" / "variant" / undefined,
// ignorePunctuation: true / false
// }
//
// Note that lazy data is only installed as a final step of initialization,
// so every Collator lazy data object has *all* these properties, never a
// subset of them.
var lazyCollatorData = std_Object_create(null);
// Step 3.
var requestedLocales = CanonicalizeLocaleList(locales);
lazyCollatorData.requestedLocales = requestedLocales;
// Steps 4-5.
//
// If we ever need more speed here at startup, we should try to detect the
// case where |options === undefined| and Object.prototype hasn't been
// mucked with. (|options| is fully consumed in this method, so it's not a
// concern that Object.prototype might be touched between now and when
// |resolveCollatorInternals| is called.) For now, just keep it simple.
if (options === undefined)
options = {};
else
options = ToObject(options);
// Compute options that impact interpretation of locale.
// Step 6.
var u = GetOption(options, "usage", "string", ["sort", "search"], "sort");
lazyCollatorData.usage = u;
// Step 10.
var opt = new Record();
lazyCollatorData.opt = opt;
// Steps 11-12.
var matcher = GetOption(options, "localeMatcher", "string", ["lookup", "best fit"], "best fit");
opt.localeMatcher = matcher;
// Step 13, unrolled.
var numericValue = GetOption(options, "numeric", "boolean", undefined, undefined);
if (numericValue !== undefined)
numericValue = numericValue ? 'true' : 'false';
opt.kn = numericValue;
var caseFirstValue = GetOption(options, "caseFirst", "string", ["upper", "lower", "false"], undefined);
opt.kf = caseFirstValue;
// Compute remaining collation options.
// Step 20.
var s = GetOption(options, "sensitivity", "string",
["base", "accent", "case", "variant"], undefined);
lazyCollatorData.rawSensitivity = s;
// Step 23.
var ip = GetOption(options, "ignorePunctuation", "boolean", undefined, false);
lazyCollatorData.ignorePunctuation = ip;
// Step 26.
//
// We've done everything that must be done now: mark the lazy data as fully
// computed and install it.
setLazyData(internals, "Collator", lazyCollatorData);
}
/**
* 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 Internationalization API Specification, 10.2.2.
*/
function Intl_Collator_supportedLocalesOf(locales /*, options*/) {
var options = arguments.length > 1 ? arguments[1] : undefined;
var availableLocales = callFunction(collatorInternalProperties.availableLocales,
collatorInternalProperties);
var requestedLocales = CanonicalizeLocaleList(locales);
return SupportedLocales(availableLocales, requestedLocales, options);
}
/**
* Collator internal properties.
*
* Spec: ECMAScript Internationalization API Specification, 9.1 and 10.2.3.
*/
var collatorInternalProperties = {
sortLocaleData: collatorSortLocaleData,
searchLocaleData: collatorSearchLocaleData,
_availableLocales: null,
availableLocales: function()
{
var locales = this._availableLocales;
if (locales)
return locales;
locales = intl_Collator_availableLocales();
addSpecialMissingLanguageTags(locales);
return (this._availableLocales = locales);
},
relevantExtensionKeys: ["co", "kn"]
};
function collatorSortLocaleData(locale) {
var collations = intl_availableCollations(locale);
callFunction(std_Array_unshift, collations, null);
return {
co: collations,
kn: ["false", "true"]
};
}
function collatorSearchLocaleData(locale) {
return {
co: [null],
kn: ["false", "true"],
// In theory the default sensitivity is locale dependent;
// in reality the CLDR/ICU default strength is always tertiary.
sensitivity: "variant"
};
}
/**
* Function to be bound and returned by Intl.Collator.prototype.format.
*
* Spec: ECMAScript Internationalization API Specification, 12.3.2.
*/
function collatorCompareToBind(x, y) {
// Steps 1.a.i-ii implemented by ECMAScript declaration binding instantiation,
// ES5.1 10.5, step 4.d.ii.
// Step 1.a.iii-v.
var X = ToString(x);
var Y = ToString(y);
return intl_CompareStrings(this, X, Y);
}
/**
* Returns a function bound to this Collator that compares x (converted to a
* String value) and y (converted to a String value),
* and returns a number less than 0 if x < y, 0 if x = y, or a number greater
* than 0 if x > y according to the sort order for the locale and collation
* options of this Collator object.
*
* Spec: ECMAScript Internationalization API Specification, 10.3.2.
*/
function Intl_Collator_compare_get() {
// Check "this Collator object" per introduction of section 10.3.
var internals = getCollatorInternals(this, "compare");
// Step 1.
if (internals.boundCompare === undefined) {
// Step 1.a.
var F = collatorCompareToBind;
// Step 1.b-d.
var bc = callFunction(FunctionBind, F, this);
internals.boundCompare = bc;
}
// Step 2.
return internals.boundCompare;
}
/**
* Returns the resolved options for a Collator object.
*
* Spec: ECMAScript Internationalization API Specification, 10.3.3 and 10.4.
*/
function Intl_Collator_resolvedOptions() {
// Check "this Collator object" per introduction of section 10.3.
var internals = getCollatorInternals(this, "resolvedOptions");
var result = {
locale: internals.locale,
usage: internals.usage,
sensitivity: internals.sensitivity,
ignorePunctuation: internals.ignorePunctuation
};
var relevantExtensionKeys = collatorInternalProperties.relevantExtensionKeys;
for (var i = 0; i < relevantExtensionKeys.length; i++) {
var key = relevantExtensionKeys[i];
var property = (key === "co") ? "collation" : collatorKeyMappings[key].property;
_DefineDataProperty(result, property, internals[property]);
}
return result;
}

View file

@ -669,6 +669,7 @@ selfhosted.inputs = [
'builtin/Function.js',
'builtin/Generator.js',
'builtin/Intl.js',
'builtin/intl/Collator.js',
'builtin/intl/DateTimeFormat.js',
'builtin/intl/IntlObject.js',
'builtin/intl/LangTagMappingsGenerated.js',