Chromium Code Reviews| Index: src/runtime/runtime-i18n.cc |
| diff --git a/src/runtime/runtime-i18n.cc b/src/runtime/runtime-i18n.cc |
| index 8b9d92ec006eb570bf14755087d97987b8d04e2d..15fe52d0d90214f6fb3da68698353a3506d1a4ca 100644 |
| --- a/src/runtime/runtime-i18n.cc |
| +++ b/src/runtime/runtime-i18n.cc |
| @@ -25,6 +25,8 @@ |
| #include "unicode/decimfmt.h" |
| #include "unicode/dtfmtsym.h" |
| #include "unicode/dtptngen.h" |
| +#include "unicode/fieldpos.h" |
| +#include "unicode/fpositer.h" |
| #include "unicode/locid.h" |
| #include "unicode/normalizer2.h" |
| #include "unicode/numfmt.h" |
| @@ -393,6 +395,140 @@ RUNTIME_FUNCTION(Runtime_InternalDateFormat) { |
| result.length()))); |
| } |
| +namespace { |
| +// The list comes from third_party/icu/source/i18n/unicode/udat.h. |
| +// They're mapped to |
| +// https://tc39.github.io/ecma402/#table-datetimeformat-components |
| +// TODO(jshin): Map UDAT.*FIELD to DateTimeFormatPartType enums |
| +// for each of which return NewStringFromStaticChars or 'AtomicString' |
| +// if available. |
| +const char* kIcuDateFieldIdToDateType[] = { |
| + "era", // UDAT_ERA_FIELD = 0, |
| + "year", // UDAT_YEAR_FIELD = 1, |
| + "month", // UDAT_MONTH_FIELD = 2, |
| + "day", // UDAT_DATE_FIELD = 3, |
| + "hour", // UDAT_HOUR_OF_DAY1_FIELD = 4, |
| + "hour", // UDAT_HOUR_OF_DAY0_FIELD = 5, |
| + "minute", // UDAT_MINUTE_FIELD = 6, |
| + "second", // UDAT_SECOND_FIELD = 7, |
| + nullptr, // UDAT_FRACTIONAL_SECOND_FIELD = 8, |
| + "weekday", // UDAT_DAY_OF_WEEK_FIELD = 9, |
| + nullptr, // UDAT_DAY_OF_YEAR_FIELD = 10, |
| + nullptr, // UDAT_DAY_OF_WEEK_IN_MONTH_FIELD = 11, |
| + nullptr, // UDAT_WEEK_OF_YEAR_FIELD = 12, |
| + nullptr, // UDAT_WEEK_OF_MONTH_FIELD = 13, |
| + "dayperiod", // UDAT_AM_PM_FIELD = 14, |
| + "hour", // UDAT_HOUR1_FIELD = 15, |
| + "hour", // UDAT_HOUR0_FIELD = 16, |
| + "timeZoneName", // UDAT_TIMEZONE_FIELD = 17, |
| + nullptr, // UDAT_YEAR_WOY_FIELD = 18, |
| + "weekday", // UDAT_DOW_LOCAL_FIELD = 19, |
| + "year", // UDAT_EXTENDED_YEAR_FIELD = 20, |
| + "day", // UDAT_JULIAN_DAY_FIELD = 21, |
| + nullptr, // UDAT_MILLISECONDS_IN_DAY_FIELD = 22, |
| + "timeZoneName", // UDAT_TIMEZONE_RFC_FIELD = 23, |
| + "timeZoneName", // UDAT_TIMEZONE_GENERIC_FIELD = 24, |
| + "weekday", // UDAT_STANDALONE_DAY_FIELD = 25, |
| + "month", // UDAT_STANDALONE_MONTH_FIELD = 26, |
| + nullptr, // UDAT_QUARTER_FIELD = 27, |
| + nullptr, // UDAT_STANDALONE_QUARTER_FIELD = 28, |
| + "timeZoneName", // UDAT_TIMEZONE_SPECIAL_FIELD = 29, |
| + "year", // UDAT_YEAR_NAME_FIELD = 30, |
| + "timeZoneName", // UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD = 31, |
| + "timeZoneName", // UDAT_TIMEZONE_ISO_FIELD = 32, |
| + "timeZoneName", // UDAT_TIMEZONE_ISO_LOCAL_FIELD = 33, |
| + nullptr, // UDAT_RELATED_YEAR_FIELD = 34, |
| + nullptr, // UDAT_TIME_SEPARATOR_FIELD = 35, |
| + nullptr, // UDAT_FIELD_COUNT = 36 |
| +}; |
| + |
| +bool AddElement(Handle<JSArray> array, int index, const char* type, |
| + const icu::UnicodeString& formatted, int32_t begin, int32_t end, |
| + Handle<Name> type_literal, Handle<Name> value_literal, |
| + Isolate* isolate) { |
|
jungshik at Google
2016/08/24 23:03:35
I guess it can be converted to lambda function if
Dan Ehrenberg
2016/08/25 16:54:45
What do you mean?
|
| + Factory* factory = isolate->factory(); |
| + Handle<JSObject> element = factory->NewJSObject(isolate->object_function()); |
| + Handle<String> value = factory->NewStringFromAsciiChecked(type); |
| + JSObject::AddProperty(element, type_literal, value, NONE); |
| + |
| + icu::UnicodeString field; |
| + formatted.extractBetween(begin, end, field); |
| + ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
| + isolate, value, factory->NewStringFromTwoByte(Vector<const uint16_t>( |
| + reinterpret_cast<const uint16_t*>(field.getBuffer()), |
| + field.length())), |
| + false); |
| + |
| + JSObject::AddProperty(element, value_literal, value, NONE); |
| + RETURN_ON_EXCEPTION_VALUE( |
| + isolate, JSObject::AddDataElement(array, index, element, NONE), false); |
| + return true; |
| +} |
| + |
| +} // namespace |
| + |
| +RUNTIME_FUNCTION(Runtime_InternalDateFormatToParts) { |
| + HandleScope scope(isolate); |
| + Factory* factory = isolate->factory(); |
| + |
| + DCHECK(args.length() == 2); |
| + |
| + CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0); |
| + CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 1); |
| + |
| + Handle<Object> value; |
| + ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, Object::ToNumber(date)); |
| + |
| + icu::SimpleDateFormat* date_format = |
| + DateFormat::UnpackDateFormat(isolate, date_format_holder); |
| + if (!date_format) return isolate->ThrowIllegalOperation(); |
| + |
| + icu::UnicodeString formatted; |
| + icu::FieldPositionIterator fpIter; |
| + icu::FieldPosition fp; |
| + UErrorCode status = U_ZERO_ERROR; |
| + date_format->format(value->Number(), formatted, &fpIter, status); |
| + if (U_FAILURE(status)) return isolate->heap()->undefined_value(); |
| + |
| + Handle<JSArray> result = factory->NewJSArray(0); |
| + Handle<Name> type_literal = factory->NewStringFromStaticChars("type"); |
| + Handle<Name> value_literal = factory->NewStringFromStaticChars("value"); |
|
jungshik at Google
2016/08/24 23:03:35
Is there a better way to represent the above two c
Dan Ehrenberg
2016/08/25 16:54:45
Yes, you can add them to the INTERNALIZED_STRING_L
|
| + |
| + int index = 0; |
| + int32_t previous_end_pos = 0; |
| + while (fpIter.next(fp)) { |
| + int32_t fieldId = fp.getField(); |
| + const char* type = kIcuDateFieldIdToDateType[fieldId]; |
| + int32_t begin_pos = fp.getBeginIndex(); |
| + int32_t end_pos = fp.getEndIndex(); |
| + if (type == nullptr) { |
| + previous_end_pos = end_pos; |
| + continue; |
| + } |
| + if (previous_end_pos < begin_pos) { |
| + if (!AddElement(result, index, "literal", formatted, previous_end_pos, |
| + begin_pos, type_literal, value_literal, isolate)) { |
| + return isolate->heap()->undefined_value(); |
| + } |
| + ++index; |
| + } |
| + if (!AddElement(result, index, type, formatted, begin_pos, end_pos, |
| + type_literal, value_literal, isolate)) { |
| + return isolate->heap()->undefined_value(); |
| + } |
| + previous_end_pos = end_pos; |
| + ++index; |
| + } |
| + int32_t length = formatted.length(); |
| + if (previous_end_pos < length) { |
| + if (!AddElement(result, index, "literal", formatted, previous_end_pos, |
| + length, type_literal, value_literal, isolate)) { |
| + return isolate->heap()->undefined_value(); |
| + } |
| + } |
| + JSObject::ValidateElements(result); |
| + return *result; |
| +} |
| RUNTIME_FUNCTION(Runtime_InternalDateParse) { |
| HandleScope scope(isolate); |