Move i18n's number-format C++ code to runtime
authorjochen@chromium.org <jochen@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 7 Aug 2013 12:14:50 +0000 (12:14 +0000)
committerjochen@chromium.org <jochen@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 7 Aug 2013 12:14:50 +0000 (12:14 +0000)
BUG=v8:2745
R=dcarney@chromium.org, mstarzinger@chromium.org

Review URL: https://codereview.chromium.org/22266009

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16099 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/extensions/i18n/i18n-extension.cc
src/extensions/i18n/number-format.cc [deleted file]
src/extensions/i18n/number-format.h [deleted file]
src/extensions/i18n/number-format.js
src/i18n.cc
src/i18n.h
src/runtime.cc
src/runtime.h
tools/gyp/v8.gyp

index b110b7d80ed2e8e20eeff55731a732bfd0b2a979..ef39d45238d0d48f109418592c27d2bef354db71 100644 (file)
@@ -31,7 +31,6 @@
 #include "break-iterator.h"
 #include "collator.h"
 #include "natives.h"
-#include "number-format.h"
 
 using v8::internal::I18NNatives;
 
@@ -47,15 +46,6 @@ Extension::Extension()
 
 v8::Handle<v8::FunctionTemplate> Extension::GetNativeFunction(
     v8::Handle<v8::String> name) {
-  // Number format and parse.
-  if (name->Equals(v8::String::New("NativeJSCreateNumberFormat"))) {
-    return v8::FunctionTemplate::New(NumberFormat::JSCreateNumberFormat);
-  } else if (name->Equals(v8::String::New("NativeJSInternalNumberFormat"))) {
-    return v8::FunctionTemplate::New(NumberFormat::JSInternalFormat);
-  } else if (name->Equals(v8::String::New("NativeJSInternalNumberParse"))) {
-    return v8::FunctionTemplate::New(NumberFormat::JSInternalParse);
-  }
-
   // Collator.
   if (name->Equals(v8::String::New("NativeJSCreateCollator"))) {
     return v8::FunctionTemplate::New(Collator::JSCreateCollator);
diff --git a/src/extensions/i18n/number-format.cc b/src/extensions/i18n/number-format.cc
deleted file mode 100644 (file)
index 1364715..0000000
+++ /dev/null
@@ -1,418 +0,0 @@
-// Copyright 2013 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-//       notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-//       copyright notice, this list of conditions and the following
-//       disclaimer in the documentation and/or other materials provided
-//       with the distribution.
-//     * Neither the name of Google Inc. nor the names of its
-//       contributors may be used to endorse or promote products derived
-//       from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// limitations under the License.
-
-#include "number-format.h"
-
-#include <string.h>
-
-#include "i18n-utils.h"
-#include "unicode/curramt.h"
-#include "unicode/dcfmtsym.h"
-#include "unicode/decimfmt.h"
-#include "unicode/locid.h"
-#include "unicode/numfmt.h"
-#include "unicode/numsys.h"
-#include "unicode/uchar.h"
-#include "unicode/ucurr.h"
-#include "unicode/unum.h"
-#include "unicode/uversion.h"
-
-namespace v8_i18n {
-
-static icu::DecimalFormat* InitializeNumberFormat(v8::Handle<v8::String>,
-                                                  v8::Handle<v8::Object>,
-                                                  v8::Handle<v8::Object>);
-static icu::DecimalFormat* CreateICUNumberFormat(const icu::Locale&,
-                                                 v8::Handle<v8::Object>);
-static void SetResolvedSettings(const icu::Locale&,
-                                icu::DecimalFormat*,
-                                v8::Handle<v8::Object>);
-
-icu::DecimalFormat* NumberFormat::UnpackNumberFormat(
-    v8::Handle<v8::Object> obj) {
-  v8::HandleScope handle_scope;
-
-  // v8::ObjectTemplate doesn't have HasInstance method so we can't check
-  // if obj is an instance of NumberFormat class. We'll check for a property
-  // that has to be in the object. The same applies to other services, like
-  // Collator and DateTimeFormat.
-  if (obj->HasOwnProperty(v8::String::New("numberFormat"))) {
-    return static_cast<icu::DecimalFormat*>(
-        obj->GetAlignedPointerFromInternalField(0));
-  }
-
-  return NULL;
-}
-
-void NumberFormat::DeleteNumberFormat(v8::Isolate* isolate,
-                                      v8::Persistent<v8::Object>* object,
-                                      void* param) {
-  // First delete the hidden C++ object.
-  // Unpacking should never return NULL here. That would only happen if
-  // this method is used as the weak callback for persistent handles not
-  // pointing to a date time formatter.
-  v8::HandleScope handle_scope(isolate);
-  v8::Local<v8::Object> handle = v8::Local<v8::Object>::New(isolate, *object);
-  delete UnpackNumberFormat(handle);
-
-  // Then dispose of the persistent handle to JS object.
-  object->Dispose(isolate);
-}
-
-void NumberFormat::JSInternalFormat(
-    const v8::FunctionCallbackInfo<v8::Value>& args) {
-  if (args.Length() != 2 || !args[0]->IsObject() || !args[1]->IsNumber()) {
-    v8::ThrowException(v8::Exception::Error(
-        v8::String::New("Formatter and numeric value have to be specified.")));
-    return;
-  }
-
-  icu::DecimalFormat* number_format = UnpackNumberFormat(args[0]->ToObject());
-  if (!number_format) {
-    v8::ThrowException(v8::Exception::Error(
-        v8::String::New("NumberFormat method called on an object "
-                        "that is not a NumberFormat.")));
-    return;
-  }
-
-  // ICU will handle actual NaN value properly and return NaN string.
-  icu::UnicodeString result;
-  number_format->format(args[1]->NumberValue(), result);
-
-  args.GetReturnValue().Set(v8::String::New(
-      reinterpret_cast<const uint16_t*>(result.getBuffer()), result.length()));
-}
-
-void NumberFormat::JSInternalParse(
-    const v8::FunctionCallbackInfo<v8::Value>& args) {
-  if (args.Length() != 2 || !args[0]->IsObject() || !args[1]->IsString()) {
-    v8::ThrowException(v8::Exception::Error(
-        v8::String::New("Formatter and string have to be specified.")));
-    return;
-  }
-
-  icu::DecimalFormat* number_format = UnpackNumberFormat(args[0]->ToObject());
-  if (!number_format) {
-    v8::ThrowException(v8::Exception::Error(
-        v8::String::New("NumberFormat method called on an object "
-                        "that is not a NumberFormat.")));
-    return;
-  }
-
-  // ICU will handle actual NaN value properly and return NaN string.
-  icu::UnicodeString string_number;
-  if (!Utils::V8StringToUnicodeString(args[1]->ToString(), &string_number)) {
-    string_number = "";
-  }
-
-  UErrorCode status = U_ZERO_ERROR;
-  icu::Formattable result;
-  // ICU 4.6 doesn't support parseCurrency call. We need to wait for ICU49
-  // to be part of Chrome.
-  // TODO(cira): Include currency parsing code using parseCurrency call.
-  // We need to check if the formatter parses all currencies or only the
-  // one it was constructed with (it will impact the API - how to return ISO
-  // code and the value).
-  number_format->parse(string_number, result, status);
-  if (U_FAILURE(status)) {
-    return;
-  }
-
-  switch (result.getType()) {
-  case icu::Formattable::kDouble:
-    args.GetReturnValue().Set(result.getDouble());
-    return;
-  case icu::Formattable::kLong:
-    args.GetReturnValue().Set(result.getLong());
-    return;
-  case icu::Formattable::kInt64:
-    args.GetReturnValue().Set(static_cast<double>(result.getInt64()));
-    return;
-  default:
-    return;
-  }
-}
-
-void NumberFormat::JSCreateNumberFormat(
-    const v8::FunctionCallbackInfo<v8::Value>& args) {
-  if (args.Length() != 3 ||
-      !args[0]->IsString() ||
-      !args[1]->IsObject() ||
-      !args[2]->IsObject()) {
-    v8::ThrowException(v8::Exception::Error(
-        v8::String::New("Internal error, wrong parameters.")));
-    return;
-  }
-
-  v8::Isolate* isolate = args.GetIsolate();
-  v8::Local<v8::ObjectTemplate> number_format_template =
-      Utils::GetTemplate(isolate);
-
-  // Create an empty object wrapper.
-  v8::Local<v8::Object> local_object = number_format_template->NewInstance();
-  // But the handle shouldn't be empty.
-  // That can happen if there was a stack overflow when creating the object.
-  if (local_object.IsEmpty()) {
-    args.GetReturnValue().Set(local_object);
-    return;
-  }
-
-  // Set number formatter as internal field of the resulting JS object.
-  icu::DecimalFormat* number_format = InitializeNumberFormat(
-      args[0]->ToString(), args[1]->ToObject(), args[2]->ToObject());
-
-  if (!number_format) {
-    v8::ThrowException(v8::Exception::Error(v8::String::New(
-        "Internal error. Couldn't create ICU number formatter.")));
-    return;
-  } else {
-    local_object->SetAlignedPointerInInternalField(0, number_format);
-
-    v8::TryCatch try_catch;
-    local_object->Set(v8::String::New("numberFormat"),
-                      v8::String::New("valid"));
-    if (try_catch.HasCaught()) {
-      v8::ThrowException(v8::Exception::Error(
-          v8::String::New("Internal error, couldn't set property.")));
-      return;
-    }
-  }
-
-  v8::Persistent<v8::Object> wrapper(isolate, local_object);
-  // Make object handle weak so we can delete iterator once GC kicks in.
-  wrapper.MakeWeak<void>(NULL, &DeleteNumberFormat);
-  args.GetReturnValue().Set(wrapper);
-  wrapper.ClearAndLeak();
-}
-
-static icu::DecimalFormat* InitializeNumberFormat(
-    v8::Handle<v8::String> locale,
-    v8::Handle<v8::Object> options,
-    v8::Handle<v8::Object> resolved) {
-  // Convert BCP47 into ICU locale format.
-  UErrorCode status = U_ZERO_ERROR;
-  icu::Locale icu_locale;
-  char icu_result[ULOC_FULLNAME_CAPACITY];
-  int icu_length = 0;
-  v8::String::AsciiValue bcp47_locale(locale);
-  if (bcp47_locale.length() != 0) {
-    uloc_forLanguageTag(*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY,
-                        &icu_length, &status);
-    if (U_FAILURE(status) || icu_length == 0) {
-      return NULL;
-    }
-    icu_locale = icu::Locale(icu_result);
-  }
-
-  icu::DecimalFormat* number_format =
-      CreateICUNumberFormat(icu_locale, options);
-  if (!number_format) {
-    // Remove extensions and try again.
-    icu::Locale no_extension_locale(icu_locale.getBaseName());
-    number_format = CreateICUNumberFormat(no_extension_locale, options);
-
-    // Set resolved settings (pattern, numbering system).
-    SetResolvedSettings(no_extension_locale, number_format, resolved);
-  } else {
-    SetResolvedSettings(icu_locale, number_format, resolved);
-  }
-
-  return number_format;
-}
-
-static icu::DecimalFormat* CreateICUNumberFormat(
-    const icu::Locale& icu_locale, v8::Handle<v8::Object> options) {
-  // Make formatter from options. Numbering system is added
-  // to the locale as Unicode extension (if it was specified at all).
-  UErrorCode status = U_ZERO_ERROR;
-  icu::DecimalFormat* number_format = NULL;
-  icu::UnicodeString style;
-  icu::UnicodeString currency;
-  if (Utils::ExtractStringSetting(options, "style", &style)) {
-    if (style == UNICODE_STRING_SIMPLE("currency")) {
-      Utils::ExtractStringSetting(options, "currency", &currency);
-
-      icu::UnicodeString display;
-      Utils::ExtractStringSetting(options, "currencyDisplay", &display);
-#if (U_ICU_VERSION_MAJOR_NUM == 4) && (U_ICU_VERSION_MINOR_NUM <= 6)
-      icu::NumberFormat::EStyles style;
-      if (display == UNICODE_STRING_SIMPLE("code")) {
-        style = icu::NumberFormat::kIsoCurrencyStyle;
-      } else if (display == UNICODE_STRING_SIMPLE("name")) {
-        style = icu::NumberFormat::kPluralCurrencyStyle;
-      } else {
-        style = icu::NumberFormat::kCurrencyStyle;
-      }
-#else  // ICU version is 4.8 or above (we ignore versions below 4.0).
-      UNumberFormatStyle style;
-      if (display == UNICODE_STRING_SIMPLE("code")) {
-        style = UNUM_CURRENCY_ISO;
-      } else if (display == UNICODE_STRING_SIMPLE("name")) {
-        style = UNUM_CURRENCY_PLURAL;
-      } else {
-        style = UNUM_CURRENCY;
-      }
-#endif
-
-      number_format = static_cast<icu::DecimalFormat*>(
-          icu::NumberFormat::createInstance(icu_locale, style,  status));
-    } else if (style == UNICODE_STRING_SIMPLE("percent")) {
-      number_format = static_cast<icu::DecimalFormat*>(
-          icu::NumberFormat::createPercentInstance(icu_locale, status));
-      if (U_FAILURE(status)) {
-        delete number_format;
-        return NULL;
-      }
-      // Make sure 1.1% doesn't go into 2%.
-      number_format->setMinimumFractionDigits(1);
-    } else {
-      // Make a decimal instance by default.
-      number_format = static_cast<icu::DecimalFormat*>(
-          icu::NumberFormat::createInstance(icu_locale, status));
-    }
-  }
-
-  if (U_FAILURE(status)) {
-    delete number_format;
-    return NULL;
-  }
-
-  // Set all options.
-  if (!currency.isEmpty()) {
-    number_format->setCurrency(currency.getBuffer(), status);
-  }
-
-  int32_t digits;
-  if (Utils::ExtractIntegerSetting(
-          options, "minimumIntegerDigits", &digits)) {
-    number_format->setMinimumIntegerDigits(digits);
-  }
-
-  if (Utils::ExtractIntegerSetting(
-          options, "minimumFractionDigits", &digits)) {
-    number_format->setMinimumFractionDigits(digits);
-  }
-
-  if (Utils::ExtractIntegerSetting(
-          options, "maximumFractionDigits", &digits)) {
-    number_format->setMaximumFractionDigits(digits);
-  }
-
-  bool significant_digits_used = false;
-  if (Utils::ExtractIntegerSetting(
-          options, "minimumSignificantDigits", &digits)) {
-    number_format->setMinimumSignificantDigits(digits);
-    significant_digits_used = true;
-  }
-
-  if (Utils::ExtractIntegerSetting(
-          options, "maximumSignificantDigits", &digits)) {
-    number_format->setMaximumSignificantDigits(digits);
-    significant_digits_used = true;
-  }
-
-  number_format->setSignificantDigitsUsed(significant_digits_used);
-
-  bool grouping;
-  if (Utils::ExtractBooleanSetting(options, "useGrouping", &grouping)) {
-    number_format->setGroupingUsed(grouping);
-  }
-
-  // Set rounding mode.
-  number_format->setRoundingMode(icu::DecimalFormat::kRoundHalfUp);
-
-  return number_format;
-}
-
-static void SetResolvedSettings(const icu::Locale& icu_locale,
-                                icu::DecimalFormat* number_format,
-                                v8::Handle<v8::Object> resolved) {
-  icu::UnicodeString pattern;
-  number_format->toPattern(pattern);
-  resolved->Set(v8::String::New("pattern"),
-                v8::String::New(reinterpret_cast<const uint16_t*>(
-                    pattern.getBuffer()), pattern.length()));
-
-  // Set resolved currency code in options.currency if not empty.
-  icu::UnicodeString currency(number_format->getCurrency());
-  if (!currency.isEmpty()) {
-    resolved->Set(v8::String::New("currency"),
-                  v8::String::New(reinterpret_cast<const uint16_t*>(
-                      currency.getBuffer()), currency.length()));
-  }
-
-  // Ugly hack. ICU doesn't expose numbering system in any way, so we have
-  // to assume that for given locale NumberingSystem constructor produces the
-  // same digits as NumberFormat would.
-  UErrorCode status = U_ZERO_ERROR;
-  icu::NumberingSystem* numbering_system =
-      icu::NumberingSystem::createInstance(icu_locale, status);
-  if (U_SUCCESS(status)) {
-    const char* ns = numbering_system->getName();
-    resolved->Set(v8::String::New("numberingSystem"), v8::String::New(ns));
-  } else {
-    resolved->Set(v8::String::New("numberingSystem"), v8::Undefined());
-  }
-  delete numbering_system;
-
-  resolved->Set(v8::String::New("useGrouping"),
-                v8::Boolean::New(number_format->isGroupingUsed()));
-
-  resolved->Set(v8::String::New("minimumIntegerDigits"),
-                v8::Integer::New(number_format->getMinimumIntegerDigits()));
-
-  resolved->Set(v8::String::New("minimumFractionDigits"),
-                v8::Integer::New(number_format->getMinimumFractionDigits()));
-
-  resolved->Set(v8::String::New("maximumFractionDigits"),
-                v8::Integer::New(number_format->getMaximumFractionDigits()));
-
-  if (resolved->HasOwnProperty(v8::String::New("minimumSignificantDigits"))) {
-    resolved->Set(v8::String::New("minimumSignificantDigits"), v8::Integer::New(
-        number_format->getMinimumSignificantDigits()));
-  }
-
-  if (resolved->HasOwnProperty(v8::String::New("maximumSignificantDigits"))) {
-    resolved->Set(v8::String::New("maximumSignificantDigits"), v8::Integer::New(
-        number_format->getMaximumSignificantDigits()));
-  }
-
-  // Set the locale
-  char result[ULOC_FULLNAME_CAPACITY];
-  status = U_ZERO_ERROR;
-  uloc_toLanguageTag(
-      icu_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status);
-  if (U_SUCCESS(status)) {
-    resolved->Set(v8::String::New("locale"), v8::String::New(result));
-  } else {
-    // This would never happen, since we got the locale from ICU.
-    resolved->Set(v8::String::New("locale"), v8::String::New("und"));
-  }
-}
-
-}  // namespace v8_i18n
diff --git a/src/extensions/i18n/number-format.h b/src/extensions/i18n/number-format.h
deleted file mode 100644 (file)
index d4dbc4d..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2013 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-//       notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-//       copyright notice, this list of conditions and the following
-//       disclaimer in the documentation and/or other materials provided
-//       with the distribution.
-//     * Neither the name of Google Inc. nor the names of its
-//       contributors may be used to endorse or promote products derived
-//       from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// limitations under the License.
-
-#ifndef V8_EXTENSIONS_I18N_NUMBER_FORMAT_H_
-#define V8_EXTENSIONS_I18N_NUMBER_FORMAT_H_
-
-#include "unicode/uversion.h"
-#include "v8.h"
-
-namespace U_ICU_NAMESPACE {
-class DecimalFormat;
-}
-
-namespace v8_i18n {
-
-class NumberFormat {
- public:
-  static void JSCreateNumberFormat(
-      const v8::FunctionCallbackInfo<v8::Value>& args);
-
-  // Helper methods for various bindings.
-
-  // Unpacks date format object from corresponding JavaScript object.
-  static icu::DecimalFormat* UnpackNumberFormat(v8::Handle<v8::Object> obj);
-
-  // Release memory we allocated for the NumberFormat once the JS object that
-  // holds the pointer gets garbage collected.
-  static void DeleteNumberFormat(v8::Isolate* isolate,
-                                 v8::Persistent<v8::Object>* object,
-                                 void* param);
-
-  // Formats number and returns corresponding string.
-  static void JSInternalFormat(const v8::FunctionCallbackInfo<v8::Value>& args);
-
-  // Parses a string and returns a number.
-  static void JSInternalParse(const v8::FunctionCallbackInfo<v8::Value>& args);
-
- private:
-  NumberFormat();
-};
-
-}  // namespace v8_i18n
-
-#endif  // V8_EXTENSIONS_I18N_NUMBER_FORMAT_H_
index 1cd3db13554b245a4cdde7e47010df513b737f1e..5722a5dc1f3cfc47c2ab8d19a345cff5d386c3c8 100644 (file)
@@ -65,8 +65,6 @@ function getNumberOption(options, property, min, max, fallback) {
  * Useful for subclassing.
  */
 function initializeNumberFormat(numberFormat, locales, options) {
-  native function NativeJSCreateNumberFormat();
-
   if (numberFormat.hasOwnProperty('__initializedIntlObject')) {
     throw new TypeError('Trying to re-initialize NumberFormat object.');
   }
@@ -148,9 +146,9 @@ function initializeNumberFormat(numberFormat, locales, options) {
   if (internalOptions.hasOwnProperty('maximumSignificantDigits')) {
     defineWEProperty(resolved, 'maximumSignificantDigits', undefined);
   }
-  var formatter = NativeJSCreateNumberFormat(requestedLocale,
-                                             internalOptions,
-                                             resolved);
+  var formatter = %CreateNumberFormat(requestedLocale,
+                                      internalOptions,
+                                      resolved);
 
   // We can't get information about number or currency style from ICU, so we
   // assume user request was fulfilled.
@@ -269,15 +267,13 @@ function initializeNumberFormat(numberFormat, locales, options) {
  * NumberFormat.
  */
 function formatNumber(formatter, value) {
-  native function NativeJSInternalNumberFormat();
-
   // Spec treats -0 and +0 as 0.
   var number = Number(value);
   if (number === -0) {
     number = 0;
   }
 
-  return NativeJSInternalNumberFormat(formatter.formatter, number);
+  return %InternalNumberFormat(formatter.formatter, number);
 }
 
 
@@ -285,9 +281,7 @@ function formatNumber(formatter, value) {
  * Returns a Number that represents string value that was passed in.
  */
 function parseNumber(formatter, value) {
-  native function NativeJSInternalNumberParse();
-
-  return NativeJSInternalNumberParse(formatter.formatter, String(value));
+  return %InternalNumberParse(formatter.formatter, String(value));
 }
 
 
index b2ccfd4985eaecf1344030125e0d6e9cc93e8e49..bd9d9c31a0b34d4613544564ee8266ec3f03aa5c 100644 (file)
 #include "i18n.h"
 
 #include "unicode/calendar.h"
+#include "unicode/curramt.h"
+#include "unicode/dcfmtsym.h"
+#include "unicode/decimfmt.h"
 #include "unicode/dtfmtsym.h"
 #include "unicode/dtptngen.h"
 #include "unicode/locid.h"
+#include "unicode/numfmt.h"
 #include "unicode/numsys.h"
 #include "unicode/smpdtfmt.h"
 #include "unicode/timezone.h"
+#include "unicode/uchar.h"
+#include "unicode/ucurr.h"
+#include "unicode/unum.h"
+#include "unicode/uversion.h"
 
 namespace v8 {
 namespace internal {
 
 namespace {
 
+bool ExtractStringSetting(Isolate* isolate,
+                          Handle<JSObject> options,
+                          const char* key,
+                          icu::UnicodeString* setting) {
+  MaybeObject* maybe_object = options->GetProperty(
+      *isolate->factory()->NewStringFromAscii(CStrVector(key)));
+  Object* object;
+  if (maybe_object->ToObject(&object) && object->IsString()) {
+    v8::String::Utf8Value utf8_string(
+        v8::Utils::ToLocal(Handle<String>(String::cast(object))));
+    *setting = icu::UnicodeString::fromUTF8(*utf8_string);
+    return true;
+  }
+  return false;
+}
+
+
+bool ExtractIntegerSetting(Isolate* isolate,
+                           Handle<JSObject> options,
+                           const char* key,
+                           int32_t* value) {
+  MaybeObject* maybe_object = options->GetProperty(
+      *isolate->factory()->NewStringFromAscii(CStrVector(key)));
+  Object* object;
+  if (maybe_object->ToObject(&object) && object->IsNumber()) {
+    object->ToInt32(value);
+    return true;
+  }
+  return false;
+}
+
+
+bool ExtractBooleanSetting(Isolate* isolate,
+                           Handle<JSObject> options,
+                           const char* key,
+                           bool* value) {
+  MaybeObject* maybe_object = options->GetProperty(
+      *isolate->factory()->NewStringFromAscii(CStrVector(key)));
+  Object* object;
+  if (maybe_object->ToObject(&object) && object->IsBoolean()) {
+    *value = object->BooleanValue();
+    return true;
+  }
+  return false;
+}
+
+
 icu::SimpleDateFormat* CreateICUDateFormat(
     Isolate* isolate,
     const icu::Locale& icu_locale,
-    Handle<Object> options) {
+    Handle<JSObject> options) {
   // Create time zone as specified by the user. We have to re-create time zone
   // since calendar takes ownership.
   icu::TimeZone* tz = NULL;
-  MaybeObject* maybe_object = options->GetProperty(
-      *isolate->factory()->NewStringFromAscii(CStrVector("timeZone")));
-  Object* timezone;
-  if (maybe_object->ToObject(&timezone) && timezone->IsString()) {
-    v8::String::Utf8Value utf8_timezone(
-        v8::Utils::ToLocal(Handle<String>(String::cast(timezone))));
-    icu::UnicodeString u_timezone(icu::UnicodeString::fromUTF8(*utf8_timezone));
-    tz = icu::TimeZone::createTimeZone(u_timezone);
+  icu::UnicodeString timezone;
+  if (ExtractStringSetting(isolate, options, "timeZone", &timezone)) {
+    tz = icu::TimeZone::createTimeZone(timezone);
   } else {
     tz = icu::TimeZone::createDefault();
   }
@@ -68,18 +118,13 @@ icu::SimpleDateFormat* CreateICUDateFormat(
   // Make formatter from skeleton. Calendar and numbering system are added
   // to the locale as Unicode extension (if they were specified at all).
   icu::SimpleDateFormat* date_format = NULL;
-  Object* skeleton;
-  maybe_object = options->GetProperty(
-      *isolate->factory()->NewStringFromAscii(CStrVector("skeleton")));
-  if (maybe_object->ToObject(&skeleton) && skeleton->IsString()) {
-    v8::String::Utf8Value utf8_skeleton(
-        v8::Utils::ToLocal(Handle<String>(String::cast(skeleton))));
-    icu::UnicodeString u_skeleton(icu::UnicodeString::fromUTF8(*utf8_skeleton));
+  icu::UnicodeString skeleton;
+  if (ExtractStringSetting(isolate, options, "skeleton", &skeleton)) {
     icu::DateTimePatternGenerator* generator =
         icu::DateTimePatternGenerator::createInstance(icu_locale, status);
     icu::UnicodeString pattern;
     if (U_SUCCESS(status)) {
-      pattern = generator->getBestPattern(u_skeleton, status);
+      pattern = generator->getBestPattern(skeleton, status);
       delete generator;
     }
 
@@ -99,10 +144,10 @@ icu::SimpleDateFormat* CreateICUDateFormat(
 }
 
 
-void SetResolvedSettings(Isolate* isolate,
-                         const icu::Locale& icu_locale,
-                         icu::SimpleDateFormat* date_format,
-                         Handle<JSObject> resolved) {
+void SetResolvedDateSettings(Isolate* isolate,
+                             const icu::Locale& icu_locale,
+                             icu::SimpleDateFormat* date_format,
+                             Handle<JSObject> resolved) {
   UErrorCode status = U_ZERO_ERROR;
   icu::UnicodeString pattern;
   date_format->toPattern(pattern);
@@ -217,6 +262,249 @@ Handle<ObjectTemplateInfo> GetEternal(Isolate* isolate) {
         field));
 }
 
+
+icu::DecimalFormat* CreateICUNumberFormat(
+    Isolate* isolate,
+    const icu::Locale& icu_locale,
+    Handle<JSObject> options) {
+  // Make formatter from options. Numbering system is added
+  // to the locale as Unicode extension (if it was specified at all).
+  UErrorCode status = U_ZERO_ERROR;
+  icu::DecimalFormat* number_format = NULL;
+  icu::UnicodeString style;
+  icu::UnicodeString currency;
+  if (ExtractStringSetting(isolate, options, "style", &style)) {
+    if (style == UNICODE_STRING_SIMPLE("currency")) {
+      icu::UnicodeString display;
+      ExtractStringSetting(isolate, options, "currency", &currency);
+      ExtractStringSetting(isolate, options, "currencyDisplay", &display);
+
+#if (U_ICU_VERSION_MAJOR_NUM == 4) && (U_ICU_VERSION_MINOR_NUM <= 6)
+      icu::NumberFormat::EStyles format_style;
+      if (display == UNICODE_STRING_SIMPLE("code")) {
+        format_style = icu::NumberFormat::kIsoCurrencyStyle;
+      } else if (display == UNICODE_STRING_SIMPLE("name")) {
+        format_style = icu::NumberFormat::kPluralCurrencyStyle;
+      } else {
+        format_style = icu::NumberFormat::kCurrencyStyle;
+      }
+#else  // ICU version is 4.8 or above (we ignore versions below 4.0).
+      UNumberFormatStyle format_style;
+      if (display == UNICODE_STRING_SIMPLE("code")) {
+        format_style = UNUM_CURRENCY_ISO;
+      } else if (display == UNICODE_STRING_SIMPLE("name")) {
+        format_style = UNUM_CURRENCY_PLURAL;
+      } else {
+        format_style = UNUM_CURRENCY;
+      }
+#endif
+
+      number_format = static_cast<icu::DecimalFormat*>(
+          icu::NumberFormat::createInstance(icu_locale, format_style,  status));
+    } else if (style == UNICODE_STRING_SIMPLE("percent")) {
+      number_format = static_cast<icu::DecimalFormat*>(
+          icu::NumberFormat::createPercentInstance(icu_locale, status));
+      if (U_FAILURE(status)) {
+        delete number_format;
+        return NULL;
+      }
+      // Make sure 1.1% doesn't go into 2%.
+      number_format->setMinimumFractionDigits(1);
+    } else {
+      // Make a decimal instance by default.
+      number_format = static_cast<icu::DecimalFormat*>(
+          icu::NumberFormat::createInstance(icu_locale, status));
+    }
+  }
+
+  if (U_FAILURE(status)) {
+    delete number_format;
+    return NULL;
+  }
+
+  // Set all options.
+  if (!currency.isEmpty()) {
+    number_format->setCurrency(currency.getBuffer(), status);
+  }
+
+  int32_t digits;
+  if (ExtractIntegerSetting(
+          isolate, options, "minimumIntegerDigits", &digits)) {
+    number_format->setMinimumIntegerDigits(digits);
+  }
+
+  if (ExtractIntegerSetting(
+          isolate, options, "minimumFractionDigits", &digits)) {
+    number_format->setMinimumFractionDigits(digits);
+  }
+
+  if (ExtractIntegerSetting(
+          isolate, options, "maximumFractionDigits", &digits)) {
+    number_format->setMaximumFractionDigits(digits);
+  }
+
+  bool significant_digits_used = false;
+  if (ExtractIntegerSetting(
+          isolate, options, "minimumSignificantDigits", &digits)) {
+    number_format->setMinimumSignificantDigits(digits);
+    significant_digits_used = true;
+  }
+
+  if (ExtractIntegerSetting(
+          isolate, options, "maximumSignificantDigits", &digits)) {
+    number_format->setMaximumSignificantDigits(digits);
+    significant_digits_used = true;
+  }
+
+  number_format->setSignificantDigitsUsed(significant_digits_used);
+
+  bool grouping;
+  if (ExtractBooleanSetting(isolate, options, "useGrouping", &grouping)) {
+    number_format->setGroupingUsed(grouping);
+  }
+
+  // Set rounding mode.
+  number_format->setRoundingMode(icu::DecimalFormat::kRoundHalfUp);
+
+  return number_format;
+}
+
+
+void SetResolvedNumberSettings(Isolate* isolate,
+                               const icu::Locale& icu_locale,
+                               icu::DecimalFormat* number_format,
+                               Handle<JSObject> resolved) {
+  icu::UnicodeString pattern;
+  number_format->toPattern(pattern);
+  JSObject::SetProperty(
+      resolved,
+      isolate->factory()->NewStringFromAscii(CStrVector("pattern")),
+      isolate->factory()->NewStringFromTwoByte(
+        Vector<const uint16_t>(
+            reinterpret_cast<const uint16_t*>(pattern.getBuffer()),
+            pattern.length())),
+      NONE,
+      kNonStrictMode);
+
+  // Set resolved currency code in options.currency if not empty.
+  icu::UnicodeString currency(number_format->getCurrency());
+  if (!currency.isEmpty()) {
+    JSObject::SetProperty(
+        resolved,
+        isolate->factory()->NewStringFromAscii(CStrVector("currency")),
+        isolate->factory()->NewStringFromTwoByte(
+          Vector<const uint16_t>(
+              reinterpret_cast<const uint16_t*>(currency.getBuffer()),
+              currency.length())),
+        NONE,
+        kNonStrictMode);
+  }
+
+  // Ugly hack. ICU doesn't expose numbering system in any way, so we have
+  // to assume that for given locale NumberingSystem constructor produces the
+  // same digits as NumberFormat/Calendar would.
+  UErrorCode status = U_ZERO_ERROR;
+  icu::NumberingSystem* numbering_system =
+      icu::NumberingSystem::createInstance(icu_locale, status);
+  if (U_SUCCESS(status)) {
+    const char* ns = numbering_system->getName();
+    JSObject::SetProperty(
+        resolved,
+        isolate->factory()->NewStringFromAscii(CStrVector("numberingSystem")),
+        isolate->factory()->NewStringFromAscii(CStrVector(ns)),
+        NONE,
+        kNonStrictMode);
+  } else {
+    JSObject::SetProperty(
+        resolved,
+        isolate->factory()->NewStringFromAscii(CStrVector("numberingSystem")),
+        isolate->factory()->undefined_value(),
+        NONE,
+        kNonStrictMode);
+  }
+  delete numbering_system;
+
+  JSObject::SetProperty(
+      resolved,
+      isolate->factory()->NewStringFromAscii(CStrVector("useGrouping")),
+      isolate->factory()->ToBoolean(number_format->isGroupingUsed()),
+      NONE,
+      kNonStrictMode);
+
+  JSObject::SetProperty(
+      resolved,
+      isolate->factory()->NewStringFromAscii(
+          CStrVector("minimumIntegerDigits")),
+      isolate->factory()->NewNumberFromInt(
+          number_format->getMinimumIntegerDigits()),
+      NONE,
+      kNonStrictMode);
+
+  JSObject::SetProperty(
+      resolved,
+      isolate->factory()->NewStringFromAscii(
+          CStrVector("minimumFractionDigits")),
+      isolate->factory()->NewNumberFromInt(
+          number_format->getMinimumFractionDigits()),
+      NONE,
+      kNonStrictMode);
+
+  JSObject::SetProperty(
+      resolved,
+      isolate->factory()->NewStringFromAscii(
+          CStrVector("maximumFractionDigits")),
+      isolate->factory()->NewNumberFromInt(
+          number_format->getMaximumFractionDigits()),
+      NONE,
+      kNonStrictMode);
+
+  if (resolved->HasLocalProperty(*isolate->factory()->NewStringFromAscii(
+          CStrVector("minimumSignificantDigits")))) {
+    JSObject::SetProperty(
+        resolved,
+        isolate->factory()->NewStringFromAscii(
+            CStrVector("minimumSignificantDigits")),
+        isolate->factory()->NewNumberFromInt(
+            number_format->getMinimumSignificantDigits()),
+        NONE,
+        kNonStrictMode);
+  }
+
+  if (resolved->HasLocalProperty(*isolate->factory()->NewStringFromAscii(
+          CStrVector("maximumSignificantDigits")))) {
+    JSObject::SetProperty(
+        resolved,
+        isolate->factory()->NewStringFromAscii(
+            CStrVector("maximumSignificantDigits")),
+        isolate->factory()->NewNumberFromInt(
+            number_format->getMaximumSignificantDigits()),
+        NONE,
+        kNonStrictMode);
+  }
+
+  // Set the locale
+  char result[ULOC_FULLNAME_CAPACITY];
+  status = U_ZERO_ERROR;
+  uloc_toLanguageTag(
+      icu_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status);
+  if (U_SUCCESS(status)) {
+    JSObject::SetProperty(
+        resolved,
+        isolate->factory()->NewStringFromAscii(CStrVector("locale")),
+        isolate->factory()->NewStringFromAscii(CStrVector(result)),
+        NONE,
+        kNonStrictMode);
+  } else {
+    // This would never happen, since we got the locale from ICU.
+    JSObject::SetProperty(
+        resolved,
+        isolate->factory()->NewStringFromAscii(CStrVector("locale")),
+        isolate->factory()->NewStringFromAscii(CStrVector("und")),
+        NONE,
+        kNonStrictMode);
+  }
+}
+
 }  // namespace
 
 
@@ -261,9 +549,10 @@ icu::SimpleDateFormat* DateFormat::InitializeDateTimeFormat(
     date_format = CreateICUDateFormat(isolate, no_extension_locale, options);
 
     // Set resolved settings (pattern, numbering system, calendar).
-    SetResolvedSettings(isolate, no_extension_locale, date_format, resolved);
+    SetResolvedDateSettings(
+        isolate, no_extension_locale, date_format, resolved);
   } else {
-    SetResolvedSettings(isolate, icu_locale, date_format, resolved);
+    SetResolvedDateSettings(isolate, icu_locale, date_format, resolved);
   }
 
   return date_format;
@@ -294,4 +583,67 @@ void DateFormat::DeleteDateFormat(v8::Isolate* isolate,
   object->Dispose(isolate);
 }
 
+
+icu::DecimalFormat* NumberFormat::InitializeNumberFormat(
+    Isolate* isolate,
+    Handle<String> locale,
+    Handle<JSObject> options,
+    Handle<JSObject> resolved) {
+  // Convert BCP47 into ICU locale format.
+  UErrorCode status = U_ZERO_ERROR;
+  icu::Locale icu_locale;
+  char icu_result[ULOC_FULLNAME_CAPACITY];
+  int icu_length = 0;
+  v8::String::Utf8Value bcp47_locale(v8::Utils::ToLocal(locale));
+  if (bcp47_locale.length() != 0) {
+    uloc_forLanguageTag(*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY,
+                        &icu_length, &status);
+    if (U_FAILURE(status) || icu_length == 0) {
+      return NULL;
+    }
+    icu_locale = icu::Locale(icu_result);
+  }
+
+  icu::DecimalFormat* number_format =
+      CreateICUNumberFormat(isolate, icu_locale, options);
+  if (!number_format) {
+    // Remove extensions and try again.
+    icu::Locale no_extension_locale(icu_locale.getBaseName());
+    number_format = CreateICUNumberFormat(
+        isolate, no_extension_locale, options);
+
+    // Set resolved settings (pattern, numbering system).
+    SetResolvedNumberSettings(
+        isolate, no_extension_locale, number_format, resolved);
+  } else {
+    SetResolvedNumberSettings(isolate, icu_locale, number_format, resolved);
+  }
+
+  return number_format;
+}
+
+
+icu::DecimalFormat* NumberFormat::UnpackNumberFormat(
+    Isolate* isolate,
+    Handle<JSObject> obj) {
+  if (obj->HasLocalProperty(*isolate->factory()->NewStringFromAscii(
+          CStrVector("numberFormat")))) {
+    return reinterpret_cast<icu::DecimalFormat*>(obj->GetInternalField(0));
+  }
+
+  return NULL;
+}
+
+
+void NumberFormat::DeleteNumberFormat(v8::Isolate* isolate,
+                                      Persistent<v8::Object>* object,
+                                      void* param) {
+  // First delete the hidden C++ object.
+  delete reinterpret_cast<icu::DecimalFormat*>(Handle<JSObject>::cast(
+      v8::Utils::OpenPersistent(object))->GetInternalField(0));
+
+  // Then dispose of the persistent handle to JS object.
+  object->Dispose(isolate);
+}
+
 } }  // namespace v8::internal
index 37c57b135bfb3626112044eb207d8221fbb51cbb..b9cbed1bbe8c3843b2a688d746beb4e8366bc1fe 100644 (file)
@@ -33,6 +33,7 @@
 #include "v8.h"
 
 namespace U_ICU_NAMESPACE {
+class DecimalFormat;
 class SimpleDateFormat;
 }
 
@@ -51,6 +52,7 @@ class I18N {
   I18N();
 };
 
+
 class DateFormat {
  public:
   // Create a formatter for the specificied locale and options. Returns the
@@ -74,6 +76,30 @@ class DateFormat {
   DateFormat();
 };
 
+
+class NumberFormat {
+ public:
+  // Create a formatter for the specificied locale and options. Returns the
+  // resolved settings for the locale / options.
+  static icu::DecimalFormat* InitializeNumberFormat(
+      Isolate* isolate,
+      Handle<String> locale,
+      Handle<JSObject> options,
+      Handle<JSObject> resolved);
+
+  // Unpacks number format object from corresponding JavaScript object.
+  static icu::DecimalFormat* UnpackNumberFormat(Isolate* isolate,
+                                                Handle<JSObject> obj);
+
+  // Release memory we allocated for the NumberFormat once the JS object that
+  // holds the pointer gets garbage collected.
+  static void DeleteNumberFormat(v8::Isolate* isolate,
+                                 Persistent<v8::Object>* object,
+                                 void* param);
+ private:
+  NumberFormat();
+};
+
 } }  // namespace v8::internal
 
 #endif  // V8_I18N_H_
index 80978f4bafaf10766c58b91549d62cc91cd42286..a1c0d750c4a0ec3ec81d245e8c8bcae90d5740d0 100644 (file)
 #include "unicode/brkiter.h"
 #include "unicode/calendar.h"
 #include "unicode/coll.h"
+#include "unicode/curramt.h"
 #include "unicode/datefmt.h"
+#include "unicode/dcfmtsym.h"
+#include "unicode/decimfmt.h"
 #include "unicode/dtfmtsym.h"
 #include "unicode/dtptngen.h"
 #include "unicode/locid.h"
 #include "unicode/numsys.h"
 #include "unicode/smpdtfmt.h"
 #include "unicode/timezone.h"
+#include "unicode/uchar.h"
+#include "unicode/ucurr.h"
 #include "unicode/uloc.h"
+#include "unicode/unum.h"
 #include "unicode/uversion.h"
 #endif
 
@@ -13665,6 +13671,121 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalDateParse) {
   }
   return *result;
 }
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateNumberFormat) {
+  HandleScope scope(isolate);
+
+  ASSERT(args.length() == 3);
+
+  CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
+
+  Handle<ObjectTemplateInfo> number_format_template =
+      I18N::GetTemplate(isolate);
+
+  // Create an empty object wrapper.
+  bool has_pending_exception = false;
+  Handle<JSObject> local_object = Execution::InstantiateObject(
+      number_format_template, &has_pending_exception);
+  if (has_pending_exception) {
+    ASSERT(isolate->has_pending_exception());
+    return Failure::Exception();
+  }
+
+  // Set number formatter as internal field of the resulting JS object.
+  icu::DecimalFormat* number_format = NumberFormat::InitializeNumberFormat(
+      isolate, locale, options, resolved);
+
+  if (!number_format) return isolate->ThrowIllegalOperation();
+
+  local_object->SetInternalField(0, reinterpret_cast<Smi*>(number_format));
+
+  RETURN_IF_EMPTY_HANDLE(isolate,
+      JSObject::SetLocalPropertyIgnoreAttributes(
+          local_object,
+          isolate->factory()->NewStringFromAscii(CStrVector("numberFormat")),
+          isolate->factory()->NewStringFromAscii(CStrVector("valid")),
+          NONE));
+
+  Persistent<v8::Object> wrapper(reinterpret_cast<v8::Isolate*>(isolate),
+                                 v8::Utils::ToLocal(local_object));
+  // Make object handle weak so we can delete the number format once GC kicks
+  // in.
+  wrapper.MakeWeak<void>(NULL, &NumberFormat::DeleteNumberFormat);
+  Handle<Object> result = Utils::OpenPersistent(wrapper);
+  wrapper.ClearAndLeak();
+  return *result;
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalNumberFormat) {
+  HandleScope scope(isolate);
+
+  ASSERT(args.length() == 2);
+
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, number_format_holder, 0);
+  CONVERT_ARG_HANDLE_CHECKED(Object, number, 1);
+
+  bool has_pending_exception = false;
+  double value = Execution::ToNumber(number, &has_pending_exception)->Number();
+  if (has_pending_exception) {
+    ASSERT(isolate->has_pending_exception());
+    return Failure::Exception();
+  }
+
+  icu::DecimalFormat* number_format =
+      NumberFormat::UnpackNumberFormat(isolate, number_format_holder);
+  if (!number_format) return isolate->ThrowIllegalOperation();
+
+  icu::UnicodeString result;
+  number_format->format(value, result);
+
+  return *isolate->factory()->NewStringFromTwoByte(
+      Vector<const uint16_t>(
+          reinterpret_cast<const uint16_t*>(result.getBuffer()),
+          result.length()));
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalNumberParse) {
+  HandleScope scope(isolate);
+
+  ASSERT(args.length() == 2);
+
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, number_format_holder, 0);
+  CONVERT_ARG_HANDLE_CHECKED(String, number_string, 1);
+
+  v8::String::Utf8Value utf8_number(v8::Utils::ToLocal(number_string));
+  icu::UnicodeString u_number(icu::UnicodeString::fromUTF8(*utf8_number));
+  icu::DecimalFormat* number_format =
+      NumberFormat::UnpackNumberFormat(isolate, number_format_holder);
+  if (!number_format) return isolate->ThrowIllegalOperation();
+
+  UErrorCode status = U_ZERO_ERROR;
+  icu::Formattable result;
+  // ICU 4.6 doesn't support parseCurrency call. We need to wait for ICU49
+  // to be part of Chrome.
+  // TODO(cira): Include currency parsing code using parseCurrency call.
+  // We need to check if the formatter parses all currencies or only the
+  // one it was constructed with (it will impact the API - how to return ISO
+  // code and the value).
+  number_format->parse(u_number, result, status);
+  if (U_FAILURE(status)) return isolate->heap()->undefined_value();
+
+  switch (result.getType()) {
+  case icu::Formattable::kDouble:
+    return *isolate->factory()->NewNumber(result.getDouble());
+  case icu::Formattable::kLong:
+    return *isolate->factory()->NewNumberFromInt(result.getLong());
+  case icu::Formattable::kInt64:
+    return *isolate->factory()->NewNumber(
+        static_cast<double>(result.getInt64()));
+  default:
+    return isolate->heap()->undefined_value();
+  }
+}
 #endif  // V8_I18N_SUPPORT
 
 
index ade7e732c0f71ac22f9b551ebad6c086530f44a9..9abec628200bcd15e38d2df7d4801b4c56581db8 100644 (file)
@@ -548,6 +548,11 @@ namespace internal {
   F(CreateDateTimeFormat, 3, 1) \
   F(InternalDateFormat, 2, 1) \
   F(InternalDateParse, 2, 1) \
+  \
+  /* Number format and parse. */ \
+  F(CreateNumberFormat, 3, 1) \
+  F(InternalNumberFormat, 2, 1) \
+  F(InternalNumberParse, 2, 1) \
 
 #else
 #define RUNTIME_FUNCTION_LIST_I18N_SUPPORT(F)
index cb9b85cd76775f26a758d4c36a282dbac24bf558..14efabdc2c8182da4d3a52b4c3d6e2b8a727e768 100644 (file)
             '../../src/extensions/i18n/i18n-extension.h',
             '../../src/extensions/i18n/i18n-utils.cc',
             '../../src/extensions/i18n/i18n-utils.h',
-            '../../src/extensions/i18n/number-format.cc',
-            '../../src/extensions/i18n/number-format.h',
           ],
           'dependencies': [
             '<(DEPTH)/third_party/icu/icu.gyp:icui18n',