Commit 18246e52 authored by Frank Tang's avatar Frank Tang Committed by Commit Bot

[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: 's avatarSathya Gunasekaran <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#54992}
parent b27c3736
......@@ -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) \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment