Index: src/runtime/runtime-i18n.cc |
diff --git a/src/runtime/runtime-i18n.cc b/src/runtime/runtime-i18n.cc |
index 8b9d92ec006eb570bf14755087d97987b8d04e2d..7fcb8025922db00d7a86f00ac64e5502b70421e8 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" |
@@ -322,7 +324,7 @@ RUNTIME_FUNCTION(Runtime_GetImplFromInitializedIntlObject) { |
Handle<Symbol> marker = isolate->factory()->intl_impl_object_symbol(); |
Handle<Object> impl = JSReceiver::GetDataProperty(obj, marker); |
- if (impl->IsTheHole(isolate)) { |
+ if (!impl->IsJSObject()) { |
THROW_NEW_ERROR_RETURN_FAILURE( |
isolate, NewTypeError(MessageTemplate::kNotIntlObject, obj)); |
} |
@@ -393,6 +395,138 @@ RUNTIME_FUNCTION(Runtime_InternalDateFormat) { |
result.length()))); |
} |
+namespace { |
+// The list comes from third_party/icu/source/i18n/unicode/udat.h. |
+// They're mapped to DateTimeFormat components listed at |
+// https://tc39.github.io/ecma402/#sec-datetimeformat-abstracts . |
+ |
+Handle<String> IcuDateFieldIdToDateType(int32_t field_id, Isolate* isolate) { |
+ switch (field_id) { |
+ case -1: |
+ return isolate->factory()->literal_string(); |
+ case UDAT_YEAR_FIELD: |
+ case UDAT_EXTENDED_YEAR_FIELD: |
+ case UDAT_YEAR_NAME_FIELD: |
+ return isolate->factory()->year_string(); |
+ case UDAT_MONTH_FIELD: |
+ case UDAT_STANDALONE_MONTH_FIELD: |
+ return isolate->factory()->month_string(); |
+ case UDAT_DATE_FIELD: |
+ return isolate->factory()->day_string(); |
+ case UDAT_HOUR_OF_DAY1_FIELD: |
+ case UDAT_HOUR_OF_DAY0_FIELD: |
+ case UDAT_HOUR1_FIELD: |
+ case UDAT_HOUR0_FIELD: |
+ return isolate->factory()->hour_string(); |
+ case UDAT_MINUTE_FIELD: |
+ return isolate->factory()->minute_string(); |
+ case UDAT_SECOND_FIELD: |
+ return isolate->factory()->second_string(); |
+ case UDAT_DAY_OF_WEEK_FIELD: |
+ case UDAT_DOW_LOCAL_FIELD: |
+ case UDAT_STANDALONE_DAY_FIELD: |
+ return isolate->factory()->weekday_string(); |
+ case UDAT_AM_PM_FIELD: |
+ return isolate->factory()->dayperiod_string(); |
+ case UDAT_TIMEZONE_FIELD: |
+ case UDAT_TIMEZONE_RFC_FIELD: |
+ case UDAT_TIMEZONE_GENERIC_FIELD: |
+ case UDAT_TIMEZONE_SPECIAL_FIELD: |
+ case UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD: |
+ case UDAT_TIMEZONE_ISO_FIELD: |
+ case UDAT_TIMEZONE_ISO_LOCAL_FIELD: |
+ return isolate->factory()->timeZoneName_string(); |
+ case UDAT_ERA_FIELD: |
+ return isolate->factory()->era_string(); |
+ default: |
+ // Other UDAT_*_FIELD's cannot show up because there is no way to specify |
+ // them via options of Intl.DateTimeFormat. |
+ UNREACHABLE(); |
+ // To prevent MSVC from issuing C4715 warning. |
+ return Handle<String>(); |
+ } |
+} |
+ |
+bool AddElement(Handle<JSArray> array, int index, int32_t field_id, |
+ const icu::UnicodeString& formatted, int32_t begin, int32_t end, |
+ Isolate* isolate) { |
+ HandleScope scope(isolate); |
+ Factory* factory = isolate->factory(); |
+ Handle<JSObject> element = factory->NewJSObject(isolate->object_function()); |
+ Handle<String> value = IcuDateFieldIdToDateType(field_id, isolate); |
+ JSObject::AddProperty(element, factory->type_string(), value, NONE); |
+ |
+ icu::UnicodeString field(formatted.tempSubStringBetween(begin, end)); |
+ 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, factory->value_string(), 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 fp_iter; |
+ icu::FieldPosition fp; |
+ UErrorCode status = U_ZERO_ERROR; |
+ date_format->format(value->Number(), formatted, &fp_iter, status); |
+ if (U_FAILURE(status)) return isolate->heap()->undefined_value(); |
+ |
+ Handle<JSArray> result = factory->NewJSArray(0); |
+ int32_t length = formatted.length(); |
+ if (length == 0) return *result; |
+ |
+ int index = 0; |
+ int32_t previous_end_pos = 0; |
+ while (fp_iter.next(fp)) { |
+ int32_t begin_pos = fp.getBeginIndex(); |
+ int32_t end_pos = fp.getEndIndex(); |
+ |
+ if (previous_end_pos < begin_pos) { |
+ if (!AddElement(result, index, -1, formatted, previous_end_pos, begin_pos, |
+ isolate)) { |
+ return isolate->heap()->undefined_value(); |
+ } |
+ ++index; |
+ } |
+ if (!AddElement(result, index, fp.getField(), formatted, begin_pos, end_pos, |
+ isolate)) { |
+ return isolate->heap()->undefined_value(); |
+ } |
+ previous_end_pos = end_pos; |
+ ++index; |
+ } |
+ if (previous_end_pos < length) { |
+ if (!AddElement(result, index, -1, formatted, previous_end_pos, length, |
+ isolate)) { |
+ return isolate->heap()->undefined_value(); |
+ } |
+ } |
+ JSObject::ValidateElements(result); |
+ return *result; |
+} |
RUNTIME_FUNCTION(Runtime_InternalDateParse) { |
HandleScope scope(isolate); |