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

Unified Diff: src/js/i18n.js

Issue 1828543007: Add new semantics + compat fallback to Intl constructor Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Add tests; make more minimal Created 4 years, 9 months 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 | « no previous file | 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 cbb664b526973beb6bb7df7d1fc256b31a4e511d..78e2fb5492449978c469203b5370aba2d8794bbb 100644
--- a/src/js/i18n.js
+++ b/src/js/i18n.js
@@ -29,6 +29,7 @@ var GlobalDate = global.Date;
var GlobalNumber = global.Number;
var GlobalRegExp = global.RegExp;
var GlobalString = global.String;
+var GlobalSymbol = global.Symbol;
var MakeError;
var MakeRangeError;
var MakeTypeError;
@@ -84,31 +85,31 @@ function InstallConstructor(object, name, func) {
%ToFastProperties(object);
}
+var fallbackSymbol = GlobalSymbol("intl fallback");
+
/**
* Adds bound method to the prototype of the given object.
*/
-function AddBoundMethod(obj, methodName, implementation, length) {
+function AddBoundMethod(obj, methodName, implementation, length, typename, compat) {
%CheckIsBootstrapping();
var internalName = %CreatePrivateSymbol(methodName);
var getter = function() {
- if (!%IsInitializedIntlObject(this)) {
- throw MakeTypeError(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 = (x, y) => implementation(this, x, y);
+ boundMethod = (x, y) => implementation(receiver, x, y);
} else if (length === 1) {
- boundMethod = x => implementation(this, x);
+ boundMethod = x => implementation(receiver, x);
} else {
boundMethod = (...args) => {
// DateTimeFormat.format needs to be 0 arg method, but can stil
// receive 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);
}
}
}
@@ -118,14 +119,51 @@ function AddBoundMethod(obj, methodName, implementation, length) {
%FunctionSetName(boundMethod, '__bound' + methodName + '__');
%FunctionRemovePrototype(boundMethod);
%SetNativeFlag(boundMethod);
- this[internalName] = boundMethod;
+ receiver[internalName] = boundMethod;
}
- return this[internalName];
+ return receiver[internalName];
};
InstallGetter(obj.prototype, methodName, getter, DONT_ENUM);
}
+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 = ObjectDefineProperty(receiver, fallbackSymbol,
+ { value: new constructor(locales, options) });
+ if (!success) {
+ throw MakeTypeError(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[fallbackSymbol];
+ if (%IsInitializedIntlObjectOfType(fallback, typename)) {
+ return fallback;
+ }
+ }
+ throw MakeTypeError(kIncompatibleMethodReceiver, method, receiver);
+ }
+ return receiver;
+}
+
+
// -------------------------------------------------------------------
var Intl = {};
@@ -1002,18 +1040,11 @@ 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);
/**
@@ -1024,11 +1055,7 @@ InstallFunction(Intl.Collator.prototype, 'resolvedOptions', function() {
throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
}
- if (!%IsInitializedIntlObjectOfType(this, 'collator')) {
- throw MakeTypeError(kResolvedOptionsCalledOnNonObject, "Collator");
- }
-
- var coll = this;
+ var coll = Unwrap(this, 'collator', Collator, 'resolvedOptions', true);
var locale = getOptimalLanguageTag(coll[resolvedSymbol].requestedLocale,
coll[resolvedSymbol].locale);
@@ -1077,7 +1104,7 @@ function compare(collator, x, y) {
};
-AddBoundMethod(Intl.Collator, 'compare', compare, 2);
+AddBoundMethod(Intl.Collator, 'compare', compare, 2, 'collator', Collator);
/**
* Verifies that the input is a well-formed ISO 4217 currency code.
@@ -1246,18 +1273,11 @@ 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);
/**
@@ -1268,11 +1288,8 @@ InstallFunction(Intl.NumberFormat.prototype, 'resolvedOptions', function() {
throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
}
- if (!%IsInitializedIntlObjectOfType(this, 'numberformat')) {
- throw MakeTypeError(kResolvedOptionsCalledOnNonObject, "NumberFormat");
- }
-
- var format = this;
+ var format = Unwrap(this, 'numberformat', NumberFormat,
+ 'resolvedOptions', true);
var locale = getOptimalLanguageTag(format[resolvedSymbol].requestedLocale,
format[resolvedSymbol].locale);
@@ -1346,8 +1363,8 @@ function parseNumber(formatter, value) {
}
-AddBoundMethod(Intl.NumberFormat, 'format', formatNumber, 1);
-AddBoundMethod(Intl.NumberFormat, 'v8Parse', parseNumber, 1);
+AddBoundMethod(Intl.NumberFormat, 'format', formatNumber, 1, 'numberformat', true);
+AddBoundMethod(Intl.NumberFormat, 'v8Parse', parseNumber, 1, 'numberformat');
/**
* Returns a string that matches LDML representation of the options object.
@@ -1640,18 +1657,11 @@ 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);
/**
@@ -1662,9 +1672,8 @@ InstallFunction(Intl.DateTimeFormat.prototype, 'resolvedOptions', function() {
throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
}
- if (!%IsInitializedIntlObjectOfType(this, 'dateformat')) {
- throw MakeTypeError(kResolvedOptionsCalledOnNonObject, "DateTimeFormat");
- }
+ var format = Unwrap(this, 'dateformat', DateTimeFormat,
+ 'resolvedOptions', true);
/**
* Maps ICU calendar names into LDML type.
@@ -1769,8 +1778,8 @@ function parseDate(formatter, value) {
// 0 because date is optional argument.
-AddBoundMethod(Intl.DateTimeFormat, 'format', formatDate, 0);
-AddBoundMethod(Intl.DateTimeFormat, 'v8Parse', parseDate, 1);
+AddBoundMethod(Intl.DateTimeFormat, 'format', formatDate, 0, 'dateformat', true);
+AddBoundMethod(Intl.DateTimeFormat, 'v8Parse', parseDate, 1, 'dateformat');
/**
@@ -1857,18 +1866,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);
/**
@@ -1880,9 +1882,7 @@ InstallFunction(Intl.v8BreakIterator.prototype, 'resolvedOptions',
throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
}
- if (!%IsInitializedIntlObjectOfType(this, 'breakiterator')) {
- throw MakeTypeError(kResolvedOptionsCalledOnNonObject, "v8BreakIterator");
- }
+ var format = Unwrap(this, 'breakiterator', v8BreakIterator, 'resolvedOptions');
var segmenter = this;
var locale =
@@ -1956,11 +1956,11 @@ function breakType(iterator) {
}
-AddBoundMethod(Intl.v8BreakIterator, 'adoptText', adoptText, 1);
-AddBoundMethod(Intl.v8BreakIterator, 'first', first, 0);
-AddBoundMethod(Intl.v8BreakIterator, 'next', next, 0);
-AddBoundMethod(Intl.v8BreakIterator, 'current', current, 0);
-AddBoundMethod(Intl.v8BreakIterator, 'breakType', breakType, 0);
+AddBoundMethod(Intl.v8BreakIterator, 'adoptText', adoptText, 1, 'breakiterator');
+AddBoundMethod(Intl.v8BreakIterator, 'first', first, 0, 'breakiterator');
+AddBoundMethod(Intl.v8BreakIterator, 'next', next, 0, 'breakiterator');
+AddBoundMethod(Intl.v8BreakIterator, 'current', current, 0, 'breakiterator');
+AddBoundMethod(Intl.v8BreakIterator, 'breakType', breakType, 0, 'breakiterator');
// Save references to Intl objects and methods we use, for added security.
var savedObjects = {
« no previous file with comments | « no previous file | src/messages.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698