[Intl] Move parseExtension from JS to C++
Bug: v8:7979 Cq-Include-Trybots: luci.v8.try:v8_linux_noi18n_rel_ng Change-Id: I367e7a7e93de267cf9b0718f193f5de3abfbf692 Reviewed-on: https://chromium-review.googlesource.com/1152556 Commit-Queue: Frank Tang <ftang@chromium.org> Reviewed-by: Sathya Gunasekaran <gsathya@chromium.org> Cr-Commit-Position: refs/heads/master@{#54992}
This commit is contained in:
parent
b27c3736c1
commit
18246e524d
src
@ -483,61 +483,6 @@ function bestFitMatcher(service, requestedLocales) {
|
||||
return lookupMatcher(service, requestedLocales);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parses Unicode extension into key - value map.
|
||||
* Returns empty object if the extension string is invalid.
|
||||
* We are not concerned with the validity of the values at this point.
|
||||
* 'attribute' in RFC 6047 is not supported. Keys without explicit
|
||||
* values are assigned UNDEFINED.
|
||||
* TODO(jshin): Fix the handling of 'attribute' (in RFC 6047, but none
|
||||
* has been defined so that it's not used) and boolean keys without
|
||||
* an explicit value.
|
||||
*/
|
||||
function parseExtension(extension) {
|
||||
var extensionSplit = %StringSplit(extension, '-', kMaxUint32);
|
||||
|
||||
// Assume ['', 'u', ...] input, but don't throw.
|
||||
if (extensionSplit.length <= 2 ||
|
||||
(extensionSplit[0] !== '' && extensionSplit[1] !== 'u')) {
|
||||
return {__proto__: null};
|
||||
}
|
||||
|
||||
// Key is {2}alphanum, value is {3,8}alphanum.
|
||||
// Some keys may not have explicit values (booleans).
|
||||
var extensionMap = {__proto__: null};
|
||||
var key = UNDEFINED;
|
||||
var value = UNDEFINED;
|
||||
for (var i = 2; i < extensionSplit.length; ++i) {
|
||||
var length = extensionSplit[i].length;
|
||||
var element = extensionSplit[i];
|
||||
if (length === 2) {
|
||||
if (!IS_UNDEFINED(key)) {
|
||||
if (!(key in extensionMap)) {
|
||||
extensionMap[key] = value;
|
||||
}
|
||||
value = UNDEFINED;
|
||||
}
|
||||
key = element;
|
||||
} else if (length >= 3 && length <= 8 && !IS_UNDEFINED(key)) {
|
||||
if (IS_UNDEFINED(value)) {
|
||||
value = element;
|
||||
} else {
|
||||
value = value + "-" + element;
|
||||
}
|
||||
} else {
|
||||
// There is a value that's too long, or that doesn't have a key.
|
||||
return {__proto__: null};
|
||||
}
|
||||
}
|
||||
if (!IS_UNDEFINED(key) && !(key in extensionMap)) {
|
||||
extensionMap[key] = value;
|
||||
}
|
||||
|
||||
return extensionMap;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Populates internalOptions object with boolean key-value pairs
|
||||
* from extensionMap and options.
|
||||
@ -928,7 +873,7 @@ function CreateNumberFormat(locales, options) {
|
||||
|
||||
// ICU prefers options to be passed using -u- extension key/values for
|
||||
// number format, so we need to build that.
|
||||
var extensionMap = parseExtension(locale.extension);
|
||||
var extensionMap = %ParseExtension(locale.extension);
|
||||
|
||||
/**
|
||||
* Map of Unicode extensions to option properties, and their values and types,
|
||||
@ -1277,7 +1222,7 @@ function CreateDateTimeFormat(locales, options) {
|
||||
// ICU prefers options to be passed using -u- extension key/values, so
|
||||
// we need to build that.
|
||||
var internalOptions = {__proto__: null};
|
||||
var extensionMap = parseExtension(locale.extension);
|
||||
var extensionMap = %ParseExtension(locale.extension);
|
||||
|
||||
/**
|
||||
* Map of Unicode extensions to option properties, and their values and types,
|
||||
|
@ -1640,6 +1640,50 @@ MaybeHandle<JSObject> Intl::CreateNumberFormat(Isolate* isolate,
|
||||
return local_object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses Unicode extension into key - value map.
|
||||
* Returns empty object if the extension string is invalid.
|
||||
* We are not concerned with the validity of the values at this point.
|
||||
* 'attribute' in RFC 6047 is not supported. Keys without explicit
|
||||
* values are assigned UNDEFINED.
|
||||
* TODO(jshin): Fix the handling of 'attribute' (in RFC 6047, but none
|
||||
* has been defined so that it's not used) and boolean keys without
|
||||
* an explicit value.
|
||||
*/
|
||||
void Intl::ParseExtension(Isolate* isolate, const std::string& extension,
|
||||
std::map<std::string, std::string>& out) {
|
||||
if (extension.compare(0, 3, "-u-") != 0) return;
|
||||
|
||||
// Key is {2}alphanum, value is {3,8}alphanum.
|
||||
// Some keys may not have explicit values (booleans).
|
||||
std::string key;
|
||||
std::string value;
|
||||
// Skip the "-u-".
|
||||
size_t start = 3;
|
||||
size_t end;
|
||||
do {
|
||||
end = extension.find("-", start);
|
||||
size_t length =
|
||||
(end == std::string::npos) ? extension.length() - start : end - start;
|
||||
std::string element = extension.substr(start, length);
|
||||
// Key is {2}alphanum
|
||||
if (length == 2) {
|
||||
if (!key.empty()) {
|
||||
out.insert(std::pair<std::string, std::string>(key, value));
|
||||
value.clear();
|
||||
}
|
||||
key = element;
|
||||
// value is {3,8}alphanum.
|
||||
} else if (length >= 3 && length <= 8 && !key.empty()) {
|
||||
value = value.empty() ? element : (value + "-" + element);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
start = end + 1;
|
||||
} while (end != std::string::npos);
|
||||
if (!key.empty()) out.insert(std::pair<std::string, std::string>(key, value));
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool IsAToZ(char ch) {
|
||||
|
@ -9,6 +9,7 @@
|
||||
#ifndef V8_OBJECTS_INTL_OBJECTS_H_
|
||||
#define V8_OBJECTS_INTL_OBJECTS_H_
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
@ -276,6 +277,10 @@ class Intl {
|
||||
// The currency is expected to an all upper case string value.
|
||||
static Handle<Smi> CurrencyDigits(Isolate* isolate, Handle<String> currency);
|
||||
|
||||
// TODO(ftang): Remove this and use ICU to the conversion in the future
|
||||
static void ParseExtension(Isolate* isolate, const std::string& extension,
|
||||
std::map<std::string, std::string>& out);
|
||||
|
||||
V8_WARN_UNUSED_RESULT static MaybeHandle<JSObject> CreateNumberFormat(
|
||||
Isolate* isolate, Handle<String> locale, Handle<JSObject> options,
|
||||
Handle<JSObject> resolved);
|
||||
|
@ -329,6 +329,25 @@ RUNTIME_FUNCTION(Runtime_PluralRulesResolvedOptions) {
|
||||
return *JSPluralRules::ResolvedOptions(isolate, plural_rules);
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_ParseExtension) {
|
||||
Factory* factory = isolate->factory();
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(1, args.length());
|
||||
CONVERT_ARG_HANDLE_CHECKED(String, extension, 0);
|
||||
std::map<std::string, std::string> map;
|
||||
Intl::ParseExtension(isolate, std::string(extension->ToCString().get()), map);
|
||||
Handle<JSObject> extension_map =
|
||||
isolate->factory()->NewJSObjectWithNullProto();
|
||||
for (std::map<std::string, std::string>::iterator it = map.begin();
|
||||
it != map.end(); it++) {
|
||||
JSObject::AddProperty(
|
||||
isolate, extension_map,
|
||||
factory->NewStringFromAsciiChecked(it->first.c_str()),
|
||||
factory->NewStringFromAsciiChecked(it->second.c_str()), NONE);
|
||||
}
|
||||
return *extension_map;
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_PluralRulesSelect) {
|
||||
HandleScope scope(isolate);
|
||||
|
||||
|
@ -228,6 +228,7 @@ namespace internal {
|
||||
F(IsInitializedIntlObjectOfType, 2, 1) \
|
||||
F(IsWellFormedCurrencyCode, 1, 1) \
|
||||
F(MarkAsInitializedIntlObjectOfType, 2, 1) \
|
||||
F(ParseExtension, 1, 1) \
|
||||
F(PluralRulesResolvedOptions, 1, 1) \
|
||||
F(PluralRulesSelect, 2, 1) \
|
||||
F(StringToLowerCaseIntl, 1, 1) \
|
||||
|
Loading…
Reference in New Issue
Block a user