Skip to content

Commit 99e8963

Browse files
Josh WolfeCommit Bot
authored andcommitted
[intl] Implement Intl.PluralRules behind --harmony-plural-rules
This feature is a stage 3 proposal implemented as a wrapper around ICU that categorizes singular/plural/etc grammatical forms based on a number and locale. Based on littledan's work started here: https://codereview.chromium.org/2736543002/ Bug: v8:5601 Cq-Include-Trybots: master.tryserver.v8:v8_linux_noi18n_rel_ng Change-Id: I4107cd28be72413ec43aa1ff0f4fe6e181a290f4 Reviewed-on: https://chromium-review.googlesource.com/562298 Commit-Queue: Josh Wolfe <[email protected]> Reviewed-by: Daniel Ehrenberg <[email protected]> Cr-Commit-Position: refs/heads/master@{#47485}
1 parent 6e13ca6 commit 99e8963

File tree

10 files changed

+557
-95
lines changed

10 files changed

+557
-95
lines changed

src/bootstrapper.cc

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4100,6 +4100,24 @@ void Bootstrapper::ExportFromRuntime(Isolate* isolate,
41004100
}
41014101
}
41024102
}
4103+
4104+
#ifdef V8_INTL_SUPPORT
4105+
{ // I n t l P l u r a l R u l e s
4106+
Handle<JSObject> plural_rules_prototype =
4107+
factory->NewJSObject(isolate->object_function(), TENURED);
4108+
// Install the @@toStringTag property on the {prototype}.
4109+
JSObject::AddProperty(
4110+
plural_rules_prototype, factory->to_string_tag_symbol(),
4111+
factory->Object_string(),
4112+
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY));
4113+
Handle<JSFunction> plural_rules_constructor = InstallFunction(
4114+
container, "PluralRules", JS_OBJECT_TYPE, PluralRules::kSize,
4115+
plural_rules_prototype, Builtins::kIllegal);
4116+
JSObject::AddProperty(plural_rules_prototype, factory->constructor_string(),
4117+
plural_rules_constructor, DONT_ENUM);
4118+
native_context->set_intl_plural_rules_function(*plural_rules_constructor);
4119+
}
4120+
#endif // V8_INTL_SUPPORT
41034121
}
41044122

41054123

@@ -4266,6 +4284,20 @@ void Genesis::InitializeGlobal_harmony_number_format_to_parts() {
42664284
name);
42674285
}
42684286

4287+
void Genesis::InitializeGlobal_harmony_plural_rules() {
4288+
if (!FLAG_harmony_plural_rules) return;
4289+
4290+
Handle<JSFunction> plural_rules(
4291+
native_context()->intl_plural_rules_function());
4292+
Handle<JSObject> intl = Handle<JSObject>::cast(
4293+
JSReceiver::GetProperty(
4294+
Handle<JSReceiver>(native_context()->global_object()),
4295+
factory()->InternalizeUtf8String("Intl"))
4296+
.ToHandleChecked());
4297+
JSObject::AddProperty(intl, factory()->InternalizeUtf8String("PluralRules"),
4298+
plural_rules, DONT_ENUM);
4299+
}
4300+
42694301
#endif // V8_INTL_SUPPORT
42704302

42714303
Handle<JSFunction> Genesis::CreateArrayBuffer(Handle<String> name,

src/contexts.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ enum ContextLookupFlags {
277277
V(INTL_NUMBER_FORMAT_FUNCTION_INDEX, JSFunction, \
278278
intl_number_format_function) \
279279
V(INTL_COLLATOR_FUNCTION_INDEX, JSFunction, intl_collator_function) \
280+
V(INTL_PLURAL_RULES_FUNCTION_INDEX, JSFunction, intl_plural_rules_function) \
280281
V(INTL_V8_BREAK_ITERATOR_FUNCTION_INDEX, JSFunction, \
281282
intl_v8_break_iterator_function) \
282283
V(JS_ARRAY_PACKED_SMI_ELEMENTS_MAP_INDEX, Map, \

src/flag-definitions.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -197,11 +197,11 @@ DEFINE_IMPLICATION(es_staging, harmony)
197197
V(harmony_promise_finally, "harmony Promise.prototype.finally")
198198

199199
#ifdef V8_INTL_SUPPORT
200-
#define HARMONY_INPROGRESS(V) \
201-
HARMONY_INPROGRESS_BASE(V) \
202-
V(harmony_number_format_to_parts, \
203-
"Intl.NumberFormat.prototype." \
204-
"formatToParts")
200+
#define HARMONY_INPROGRESS(V) \
201+
HARMONY_INPROGRESS_BASE(V) \
202+
V(harmony_number_format_to_parts, \
203+
"Intl.NumberFormat.prototype.formatToParts") \
204+
V(harmony_plural_rules, "Intl.PluralRules")
205205
#else
206206
#define HARMONY_INPROGRESS(V) HARMONY_INPROGRESS_BASE(V)
207207
#endif

src/js/intl.js

Lines changed: 107 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ var GlobalIntl = global.Intl;
2424
var GlobalIntlDateTimeFormat = GlobalIntl.DateTimeFormat;
2525
var GlobalIntlNumberFormat = GlobalIntl.NumberFormat;
2626
var GlobalIntlCollator = GlobalIntl.Collator;
27+
var GlobalIntlPluralRules = utils.ImportNow("PluralRules");
2728
var GlobalIntlv8BreakIterator = GlobalIntl.v8BreakIterator;
2829
var GlobalNumber = global.Number;
2930
var GlobalRegExp = global.RegExp;
@@ -32,6 +33,7 @@ var IntlFallbackSymbol = utils.ImportNow("intl_fallback_symbol");
3233
var InternalArray = utils.InternalArray;
3334
var MaxSimple;
3435
var ObjectHasOwnProperty = global.Object.prototype.hasOwnProperty;
36+
var ObjectKeys = global.Object.keys;
3537
var patternSymbol = utils.ImportNow("intl_pattern_symbol");
3638
var resolvedSymbol = utils.ImportNow("intl_resolved_symbol");
3739
var StringSubstr = GlobalString.prototype.substr;
@@ -124,7 +126,8 @@ var AVAILABLE_LOCALES = {
124126
'collator': UNDEFINED,
125127
'numberformat': UNDEFINED,
126128
'dateformat': UNDEFINED,
127-
'breakiterator': UNDEFINED
129+
'breakiterator': UNDEFINED,
130+
'pluralrules': UNDEFINED,
128131
};
129132

130133
/**
@@ -190,7 +193,7 @@ var SERVICE_RE = UNDEFINED;
190193
function GetServiceRE() {
191194
if (IS_UNDEFINED(SERVICE_RE)) {
192195
SERVICE_RE =
193-
new GlobalRegExp('^(collator|numberformat|dateformat|breakiterator)$');
196+
new GlobalRegExp('^(' + %_Call(ArrayJoin, ObjectKeys(AVAILABLE_LOCALES), '|') + ')$');
194197
}
195198
return SERVICE_RE;
196199
}
@@ -1072,6 +1075,108 @@ function compare(collator, x, y) {
10721075

10731076
AddBoundMethod(GlobalIntlCollator, 'compare', compare, 2, 'collator', false);
10741077

1078+
function PluralRulesConstructor() {
1079+
if (IS_UNDEFINED(new.target)) {
1080+
throw %make_type_error(kConstructorNotFunction, "PluralRules");
1081+
}
1082+
1083+
var locales = arguments[0];
1084+
var options = arguments[1];
1085+
1086+
if (IS_UNDEFINED(options)) {
1087+
options = {};
1088+
}
1089+
1090+
var getOption = getGetOption(options, 'pluralrules');
1091+
1092+
var locale = resolveLocale('pluralrules', locales, options);
1093+
1094+
var internalOptions = {};
1095+
defineWEProperty(internalOptions, 'type', getOption(
1096+
'type', 'string', ['cardinal', 'ordinal'], 'cardinal'));
1097+
1098+
SetNumberFormatDigitOptions(internalOptions, options, 0, 3);
1099+
1100+
var requestedLocale = locale.locale;
1101+
var resolved = %object_define_properties({}, {
1102+
type: {value: internalOptions.type, writable: true},
1103+
locale: {writable: true},
1104+
maximumFractionDigits: {writable: true},
1105+
minimumFractionDigits: {writable: true},
1106+
minimumIntegerDigits: {writable: true},
1107+
requestedLocale: {value: requestedLocale, writable: true},
1108+
});
1109+
if (HAS_OWN_PROPERTY(internalOptions, 'minimumSignificantDigits')) {
1110+
defineWEProperty(resolved, 'minimumSignificantDigits', UNDEFINED);
1111+
}
1112+
if (HAS_OWN_PROPERTY(internalOptions, 'maximumSignificantDigits')) {
1113+
defineWEProperty(resolved, 'maximumSignificantDigits', UNDEFINED);
1114+
}
1115+
defineWEProperty(resolved, 'pluralCategories', []);
1116+
var pluralRules = %CreatePluralRules(requestedLocale, internalOptions,
1117+
resolved);
1118+
1119+
%MarkAsInitializedIntlObjectOfType(pluralRules, 'pluralrules');
1120+
pluralRules[resolvedSymbol] = resolved;
1121+
1122+
return pluralRules;
1123+
}
1124+
%SetCode(GlobalIntlPluralRules, PluralRulesConstructor);
1125+
1126+
DEFINE_METHOD(
1127+
GlobalIntlPluralRules.prototype,
1128+
resolvedOptions() {
1129+
if (!%IsInitializedIntlObjectOfType(this, 'pluralrules')) {
1130+
throw %make_type_error(kIncompatibleMethodReceiver,
1131+
'Intl.PluralRules.prototype.resolvedOptions',
1132+
this);
1133+
}
1134+
1135+
var result = {
1136+
locale: this[resolvedSymbol].locale,
1137+
type: this[resolvedSymbol].type,
1138+
minimumIntegerDigits: this[resolvedSymbol].minimumIntegerDigits,
1139+
minimumFractionDigits: this[resolvedSymbol].minimumFractionDigits,
1140+
maximumFractionDigits: this[resolvedSymbol].maximumFractionDigits,
1141+
};
1142+
1143+
if (HAS_OWN_PROPERTY(this[resolvedSymbol], 'minimumSignificantDigits')) {
1144+
defineWECProperty(result, 'minimumSignificantDigits',
1145+
this[resolvedSymbol].minimumSignificantDigits);
1146+
}
1147+
1148+
if (HAS_OWN_PROPERTY(this[resolvedSymbol], 'maximumSignificantDigits')) {
1149+
defineWECProperty(result, 'maximumSignificantDigits',
1150+
this[resolvedSymbol].maximumSignificantDigits);
1151+
}
1152+
1153+
defineWECProperty(result, 'pluralCategories',
1154+
this[resolvedSymbol].pluralCategories);
1155+
1156+
return result;
1157+
}
1158+
);
1159+
1160+
DEFINE_METHOD(
1161+
GlobalIntlPluralRules,
1162+
supportedLocalesOf(locales) {
1163+
return supportedLocalesOf('pluralrules', locales, arguments[1]);
1164+
}
1165+
);
1166+
1167+
DEFINE_METHOD(
1168+
GlobalIntlPluralRules.prototype,
1169+
select(value) {
1170+
if (!%IsInitializedIntlObjectOfType(this, 'pluralrules')) {
1171+
throw %make_type_error(kIncompatibleMethodReceiver,
1172+
'Intl.PluralRules.prototype.select',
1173+
this);
1174+
}
1175+
1176+
return %PluralRulesSelect(this, TO_NUMBER(value) + 0);
1177+
}
1178+
);
1179+
10751180
/**
10761181
* Verifies that the input is a well-formed ISO 4217 currency code.
10771182
* Don't uppercase to test. It could convert invalid code into a valid one.

0 commit comments

Comments
 (0)