Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(529)

Unified Diff: src/js/i18n.js

Issue 2582993002: [intl] Add new semantics + compat fallback to Intl constructor (Closed)
Patch Set: reformatting Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/heap-symbols.h ('k') | src/messages.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/js/i18n.js
diff --git a/src/js/i18n.js b/src/js/i18n.js
index 803f55054de5c6673165f6965ba06f7f352496a7..15e87dfa7c1f26f1f6cf167e0221dd50ccd3f95c 100644
--- a/src/js/i18n.js
+++ b/src/js/i18n.js
@@ -23,6 +23,7 @@ var GlobalDate = global.Date;
var GlobalNumber = global.Number;
var GlobalRegExp = global.RegExp;
var GlobalString = global.String;
+var IntlFallbackSymbol = utils.ImportNow("intl_fallback_symbol");
var InstallFunctions = utils.InstallFunctions;
var InstallGetter = utils.InstallGetter;
var InternalArray = utils.InternalArray;
@@ -57,7 +58,8 @@ function InstallConstructor(object, name, func) {
/**
* Adds bound method to the prototype of the given object.
*/
-function AddBoundMethod(obj, methodName, implementation, length, type) {
+function AddBoundMethod(obj, methodName, implementation, length, typename,
+ compat) {
%CheckIsBootstrapping();
var internalName = %CreatePrivateSymbol(methodName);
// Making getter an anonymous function will cause
@@ -66,32 +68,30 @@ function AddBoundMethod(obj, methodName, implementation, length, type) {
// than (as utils.InstallGetter would) on the SharedFunctionInfo
// associated with all functions returned from AddBoundMethod.
var getter = ANONYMOUS_FUNCTION(function() {
- if (!%IsInitializedIntlObjectOfType(this, type)) {
- throw %make_type_error(kMethodCalledOnWrongObject, methodName);
- }
- if (IS_UNDEFINED(this[internalName])) {
+ var receiver = Unwrap(this, typename, obj, methodName, compat);
+ if (IS_UNDEFINED(receiver[internalName])) {
var boundMethod;
if (IS_UNDEFINED(length) || length === 2) {
boundMethod =
- ANONYMOUS_FUNCTION((fst, snd) => implementation(this, fst, snd));
+ ANONYMOUS_FUNCTION((fst, snd) => implementation(receiver, fst, snd));
} else if (length === 1) {
- boundMethod = ANONYMOUS_FUNCTION(fst => implementation(this, fst));
+ boundMethod = ANONYMOUS_FUNCTION(fst => implementation(receiver, fst));
} else {
boundMethod = ANONYMOUS_FUNCTION((...args) => {
// DateTimeFormat.format needs to be 0 arg method, but can still
// receive an optional dateValue param. If one was provided, pass it
// along.
if (args.length > 0) {
- return implementation(this, args[0]);
+ return implementation(receiver, args[0]);
} else {
- return implementation(this);
+ return implementation(receiver);
}
});
}
%SetNativeFlag(boundMethod);
- this[internalName] = boundMethod;
+ receiver[internalName] = boundMethod;
}
- return this[internalName];
+ return receiver[internalName];
});
%FunctionRemovePrototype(getter);
@@ -99,6 +99,43 @@ function AddBoundMethod(obj, methodName, implementation, length, type) {
%SetNativeFlag(getter);
}
+function IntlConstruct(receiver, constructor, initializer, newTarget, args,
+ compat) {
+ var locales = args[0];
+ var options = args[1];
+
+ if (IS_UNDEFINED(newTarget)) {
+ if (compat && receiver instanceof constructor) {
+ let success = %object_define_property(receiver, IntlFallbackSymbol,
+ { value: new constructor(locales, options) });
+ if (!success) {
+ throw %make_type_error(kReinitializeIntl, constructor);
+ }
+ return receiver;
+ }
+
+ return new constructor(locales, options);
+ }
+
+ return initializer(receiver, locales, options);
+}
+
+
+
+function Unwrap(receiver, typename, constructor, method, compat) {
+ if (!%IsInitializedIntlObjectOfType(receiver, typename)) {
+ if (compat && receiver instanceof constructor) {
+ let fallback = receiver[IntlFallbackSymbol];
+ if (%IsInitializedIntlObjectOfType(fallback, typename)) {
+ return fallback;
+ }
+ }
+ throw %make_type_error(kIncompatibleMethodReceiver, method, receiver);
+ }
+ return receiver;
+}
+
+
// -------------------------------------------------------------------
var Intl = {};
@@ -1029,29 +1066,18 @@ function initializeCollator(collator, locales, options) {
*
* @constructor
*/
-InstallConstructor(Intl, 'Collator', function() {
- var locales = arguments[0];
- var options = arguments[1];
-
- if (!this || this === Intl) {
- // Constructor is called as a function.
- return new Intl.Collator(locales, options);
- }
-
- return initializeCollator(TO_OBJECT(this), locales, options);
- }
-);
+function Collator() {
+ return IntlConstruct(this, Collator, initializeCollator, new.target,
+ arguments);
+}
+InstallConstructor(Intl, 'Collator', Collator);
/**
* Collator resolvedOptions method.
*/
InstallFunction(Intl.Collator.prototype, 'resolvedOptions', function() {
- if (!%IsInitializedIntlObjectOfType(this, 'collator')) {
- throw %make_type_error(kResolvedOptionsCalledOnNonObject, "Collator");
- }
-
- var coll = this;
+ var coll = Unwrap(this, 'collator', Collator, 'resolvedOptions', false);
var locale = getOptimalLanguageTag(coll[resolvedSymbol].requestedLocale,
coll[resolvedSymbol].locale);
@@ -1096,7 +1122,7 @@ function compare(collator, x, y) {
};
-AddBoundMethod(Intl.Collator, 'compare', compare, 2, 'collator');
+AddBoundMethod(Intl.Collator, 'compare', compare, 2, 'collator', false);
/**
* Verifies that the input is a well-formed ISO 4217 currency code.
@@ -1262,29 +1288,19 @@ function initializeNumberFormat(numberFormat, locales, options) {
*
* @constructor
*/
-InstallConstructor(Intl, 'NumberFormat', function() {
- var locales = arguments[0];
- var options = arguments[1];
-
- if (!this || this === Intl) {
- // Constructor is called as a function.
- return new Intl.NumberFormat(locales, options);
- }
-
- return initializeNumberFormat(TO_OBJECT(this), locales, options);
- }
-);
+function NumberFormat() {
+ return IntlConstruct(this, NumberFormat, initializeNumberFormat, new.target,
+ arguments, true);
+}
+InstallConstructor(Intl, 'NumberFormat', NumberFormat);
/**
* NumberFormat resolvedOptions method.
*/
InstallFunction(Intl.NumberFormat.prototype, 'resolvedOptions', function() {
- if (!%IsInitializedIntlObjectOfType(this, 'numberformat')) {
- throw %make_type_error(kResolvedOptionsCalledOnNonObject, "NumberFormat");
- }
-
- var format = this;
+ var format = Unwrap(this, 'numberformat', NumberFormat,
+ 'resolvedOptions', true);
var locale = getOptimalLanguageTag(format[resolvedSymbol].requestedLocale,
format[resolvedSymbol].locale);
@@ -1345,7 +1361,8 @@ function formatNumber(formatter, value) {
}
-AddBoundMethod(Intl.NumberFormat, 'format', formatNumber, 1, 'numberformat');
+AddBoundMethod(Intl.NumberFormat, 'format', formatNumber, 1, 'numberformat',
+ true);
/**
* Returns a string that matches LDML representation of the options object.
@@ -1638,27 +1655,19 @@ function initializeDateTimeFormat(dateFormat, locales, options) {
*
* @constructor
*/
-InstallConstructor(Intl, 'DateTimeFormat', function() {
- var locales = arguments[0];
- var options = arguments[1];
-
- if (!this || this === Intl) {
- // Constructor is called as a function.
- return new Intl.DateTimeFormat(locales, options);
- }
-
- return initializeDateTimeFormat(TO_OBJECT(this), locales, options);
- }
-);
+function DateTimeFormat() {
+ return IntlConstruct(this, DateTimeFormat, initializeDateTimeFormat,
+ new.target, arguments, true);
+}
+InstallConstructor(Intl, 'DateTimeFormat', DateTimeFormat);
/**
* DateTimeFormat resolvedOptions method.
*/
InstallFunction(Intl.DateTimeFormat.prototype, 'resolvedOptions', function() {
- if (!%IsInitializedIntlObjectOfType(this, 'dateformat')) {
- throw %make_type_error(kResolvedOptionsCalledOnNonObject, "DateTimeFormat");
- }
+ var format = Unwrap(this, 'dateformat', DateTimeFormat,
+ 'resolvedOptions', true);
/**
* Maps ICU calendar names to LDML/BCP47 types for key 'ca'.
@@ -1671,7 +1680,6 @@ InstallFunction(Intl.DateTimeFormat.prototype, 'resolvedOptions', function() {
'ethiopic-amete-alem': 'ethioaa'
};
- var format = this;
var fromPattern = fromLDMLString(format[resolvedSymbol][patternSymbol]);
var userCalendar = ICU_CALENDAR_MAP[format[resolvedSymbol].calendar];
if (IS_UNDEFINED(userCalendar)) {
@@ -1758,7 +1766,8 @@ function FormatDateToParts(dateValue) {
// 0 because date is optional argument.
-AddBoundMethod(Intl.DateTimeFormat, 'format', formatDate, 0, 'dateformat');
+AddBoundMethod(Intl.DateTimeFormat, 'format', formatDate, 0, 'dateformat',
+ true);
/**
@@ -1847,18 +1856,11 @@ function initializeBreakIterator(iterator, locales, options) {
*
* @constructor
*/
-InstallConstructor(Intl, 'v8BreakIterator', function() {
- var locales = arguments[0];
- var options = arguments[1];
-
- if (!this || this === Intl) {
- // Constructor is called as a function.
- return new Intl.v8BreakIterator(locales, options);
- }
-
- return initializeBreakIterator(TO_OBJECT(this), locales, options);
- }
-);
+function v8BreakIterator() {
+ return IntlConstruct(this, v8BreakIterator, initializeBreakIterator,
+ new.target, arguments);
+}
+InstallConstructor(Intl, 'v8BreakIterator', v8BreakIterator);
/**
@@ -1870,11 +1872,9 @@ InstallFunction(Intl.v8BreakIterator.prototype, 'resolvedOptions',
throw %make_type_error(kOrdinaryFunctionCalledAsConstructor);
}
- if (!%IsInitializedIntlObjectOfType(this, 'breakiterator')) {
- throw %make_type_error(kResolvedOptionsCalledOnNonObject, "v8BreakIterator");
- }
+ var segmenter = Unwrap(this, 'breakiterator', v8BreakIterator,
+ 'resolvedOptions', false);
- var segmenter = this;
var locale =
getOptimalLanguageTag(segmenter[resolvedSymbol].requestedLocale,
segmenter[resolvedSymbol].locale);
« no previous file with comments | « src/heap-symbols.h ('k') | src/messages.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698