Bug 769872 - Add self-hosted JavaScript core of Intl constructors Collator, NumberFormat, DateTimeFormat (part 10). r=jwalden
authorNorbert Lindenberg <mozilladev@lindenbergsoftware.com>
Fri, 22 Feb 2013 15:31:07 -0800
changeset 123025 f9b5cfcd1ca74a38cb4c9e80d733b984d6c97792
parent 123024 6f1770a17c7a55554a1454a5b150e5e0d032b98f
child 123026 ca9fbb261ec706089a2a98a0bfaa1d98de458985
push id24372
push useremorley@mozilla.com
push dateWed, 27 Feb 2013 13:22:59 +0000
treeherdermozilla-central@0a91da5f5eab [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwalden
bugs769872
milestone22.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 769872 - Add self-hosted JavaScript core of Intl constructors Collator, NumberFormat, DateTimeFormat (part 10). r=jwalden
js/src/builtin/Intl.js
js/src/builtin/Utilities.js
--- a/js/src/builtin/Intl.js
+++ b/js/src/builtin/Intl.js
@@ -849,8 +849,227 @@ function GetNumberOption(options, proper
 
 
 // ??? stub
 var runtimeAvailableLocales = (function () {
     var o = std_Object_create(null);
     o[RuntimeDefaultLocale()] = true;
     return addOldStyleLanguageTags(o);
 }());
+
+
+/********** Property access for Intl objects **********/
+
+
+/**
+ * Set a normal public property p of o to value v, but use Object.defineProperty
+ * to avoid interference from setters on Object.prototype.
+ */
+function defineProperty(o, p, v) {
+    std_Object_defineProperty(o, p, {value: v, writable: true, enumerable: true, configurable: true});
+}
+
+
+/**
+ * Weak map holding objects with the properties specified as "internal" for
+ * all Intl API objects. Presence of an object as a key within this map is
+ * considered equivalent to having the [[initializedIntlObject]] internal
+ * property set to true on this object.
+ *
+ * Ideally we'd be using private symbols for internal properties, but
+ * SpiderMonkey doesn't have those yet.
+ */
+var internalsMap = new WeakMap();
+
+
+/**
+ * Create an object holding the properties specified as "internal" for
+ * an Intl API object. This call is equivalent to setting the
+ * [[initializedIntlObject]] internal property of o to true.
+ */
+function initializeIntlObject(o) {
+    assert(IsObject(o), "initializeIntlObject");
+    var internals = std_Object_create(null);
+    callFunction(std_WeakMap_set, internalsMap, o, internals);
+    return internals;
+}
+
+
+/**
+ * Return whether the object has been initialized as an Intl object, equivalent
+ * to testing whether the [[initializedIntlObject]] internal property of o is
+ * true.
+ */
+function isInitializedIntlObject(o) {
+    return callFunction(std_WeakMap_has, internalsMap, o);
+}
+
+
+/**
+ * Returns the object holding the internal properties of o.
+ */
+function getInternals(o) {
+    return callFunction(std_WeakMap_get, internalsMap, o);
+}
+
+
+/**
+ * Check that the object on which certain functions are called
+ * meet the requirements for "this Collator object", "this NumberFormat object",
+ * "this DateTimeFormat object". If it meets the requirements, return the
+ * object holding its internal properties.
+ *
+ * Spec: ECMAScript Internationalization API Specification, 10.3.
+ * Spec: ECMAScript Internationalization API Specification, 11.3.
+ * Spec: ECMAScript Internationalization API Specification, 12.3.
+ */
+function checkIntlAPIObject(o, className, methodName) {
+    assert(typeof className === "string", "checkIntlAPIObject");
+    var internals = getInternals(o);
+    if (internals === undefined || internals["initialized" + className] !== true)
+        ThrowError(JSMSG_INTL_OBJECT_NOT_INITED, className, methodName, className);
+    assert(IsObject(o), "checkIntlAPIObject");
+    return internals;
+}
+
+
+/********** 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"]}
+};
+
+
+/**
+ * Initializes an object as a Collator.
+ *
+ * Spec: ECMAScript Internationalization API Specification, 10.1.1.
+ */
+function InitializeCollator(collator, locales, options) {
+    assert(IsObject(collator), "InitializeCollator");
+
+    // Step 1.
+    if (isInitializedIntlObject(collator))
+        ThrowError(JSMSG_INTL_OBJECT_REINITED);
+
+    // Step 2.
+    var internals = initializeIntlObject(collator);
+
+    // Step 3.
+    var requestedLocales = CanonicalizeLocaleList(locales);
+
+    // Steps 4-5.
+    if (options === undefined)
+        options = {};
+    else
+        options = ToObject(options);
+
+    // Compute options that impact interpretation of locale.
+    // Steps 6-7.
+    var u = GetOption(options, "usage", "string", ["sort", "search"], "sort");
+    internals.usage = u;
+
+    // Step 8.
+    var Collator = collatorInternalProperties;
+
+    // Step 9.
+    var localeData = u === "sort" ? Collator.sortLocaleData : Collator.searchLocaleData;
+
+    // Step 10.
+    var opt = new Record();
+
+    // Steps 11-12.
+    var matcher = GetOption(options, "localeMatcher", "string", ["lookup", "best fit"], "best fit");
+    opt.localeMatcher = matcher;
+
+    // Check all allowed options properties and convert them to extension keys.
+    // Steps 13-13.a.
+    var key, mapping, property, value;
+    for (key in collatorKeyMappings) {
+        if (callFunction(std_Object_hasOwnProperty, collatorKeyMappings, key)) {
+            mapping = collatorKeyMappings[key];
+    
+            // Step 13.b.
+            value = GetOption(options, mapping.property, mapping.type, mapping.values, undefined);
+    
+            // Step 13.c.
+            if (mapping.type === "boolean" && value !== undefined)
+                value = callFunction(std_Boolean_toString, value);
+    
+            // Step 13.d.
+            opt[key] = value;
+        }
+    }
+
+    // Compute effective locale.
+    // Step 14.
+    var relevantExtensionKeys = Collator.relevantExtensionKeys;
+
+    // Step 15.
+    var r = ResolveLocale(Collator.availableLocales,
+                          requestedLocales, opt,
+                          relevantExtensionKeys,
+                          localeData);
+    // Step 16.
+    internals.locale = r.locale;
+
+    // Steps 17-19.
+    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.
+        internals[property] = value;
+
+        // Step 19.e.
+        i++;
+    }
+
+    // Compute remaining collation options.
+    // Steps 20-21.
+    var s = GetOption(options, "sensitivity", "string",
+                      ["base", "accent", "case", "variant"], undefined);
+    if (s === undefined) {
+        if (u === "sort") {
+            // Step 21.a.
+            s = "variant";
+        } else {
+            // Step 21.b.
+            var dataLocale = r.dataLocale;
+            var dataLocaleData = localeData(dataLocale);
+            s = dataLocaleData.sensitivity;
+        }
+    }
+
+    // Step 22.
+    internals.sensitivity = s;
+
+    // Steps 23-24.
+    var ip = GetOption(options, "ignorePunctuation", "boolean", undefined, false);
+    internals.ignorePunctuation = ip;
+
+    // Step 25.
+    internals.boundFormat = undefined;
+
+    // Step 26.
+    internals.initializedCollator = true;
+}
--- a/js/src/builtin/Utilities.js
+++ b/js/src/builtin/Utilities.js
@@ -45,16 +45,19 @@ var std_String_indexOf = String.prototyp
 var std_String_lastIndexOf = String.prototype.lastIndexOf;
 var std_String_match = String.prototype.match;
 var std_String_replace = String.prototype.replace;
 var std_String_split = String.prototype.split;
 var std_String_startsWith = String.prototype.startsWith;
 var std_String_substring = String.prototype.substring;
 var std_String_toLowerCase = String.prototype.toLowerCase;
 var std_String_toUpperCase = String.prototype.toUpperCase;
+var std_WeakMap_get = WeakMap.prototype.get;
+var std_WeakMap_has = WeakMap.prototype.has;
+var std_WeakMap_set = WeakMap.prototype.set;
 
 
 /********** List specification type **********/
 
 
 /* Spec: ECMAScript Language Specification, 5.1 edition, 8.8 */
 function List() {
     if (IS_UNDEFINED(List.prototype)) {