Add implementation specific date parsing (#4576)

It is compatible with Firefox and Chrome.

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg
2021-02-09 15:03:06 +01:00
committed by GitHub
parent 53aed02762
commit ec872818c2
2 changed files with 59 additions and 40 deletions
@@ -86,7 +86,7 @@ ecma_date_parse_date_chars (const lit_utf8_byte_t **str_p, /**< pointer to the c
static bool static bool
ecma_date_parse_special_char (const lit_utf8_byte_t **str_p, /**< pointer to the cesu8 string */ ecma_date_parse_special_char (const lit_utf8_byte_t **str_p, /**< pointer to the cesu8 string */
const lit_utf8_byte_t *str_end_p, /**< pointer to the end of the string */ const lit_utf8_byte_t *str_end_p, /**< pointer to the end of the string */
const lit_utf8_byte_t expected_char) /**< expected character */ ecma_char_t expected_char) /**< expected character */
{ {
if ((*str_p < str_end_p) && (**str_p == expected_char)) if ((*str_p < str_end_p) && (**str_p == expected_char))
{ {
@@ -97,6 +97,16 @@ ecma_date_parse_special_char (const lit_utf8_byte_t **str_p, /**< pointer to the
return false; return false;
} /* ecma_date_parse_special_char */ } /* ecma_date_parse_special_char */
static inline bool JERRY_ATTR_ALWAYS_INLINE
ecma_date_check_two_chars (const lit_utf8_byte_t *str_p, /**< pointer to the cesu8 string */
const lit_utf8_byte_t *str_end_p, /**< pointer to the end of the string */
ecma_char_t expected_char1, /**< first expected character */
ecma_char_t expected_char2) /**< second expected character */
{
return (str_p < str_end_p
&& (*str_p == expected_char1 || *str_p == expected_char2));
} /* ecma_date_check_two_chars */
/** /**
* Helper function to try to parse a 4-5-6 digit year with optional negative sign in a date string * Helper function to try to parse a 4-5-6 digit year with optional negative sign in a date string
* *
@@ -109,7 +119,7 @@ static ecma_number_t
ecma_date_parse_year (const lit_utf8_byte_t **str_p, /**< pointer to the cesu8 string */ ecma_date_parse_year (const lit_utf8_byte_t **str_p, /**< pointer to the cesu8 string */
const lit_utf8_byte_t *str_end_p) /**< pointer to the end of the string */ const lit_utf8_byte_t *str_end_p) /**< pointer to the end of the string */
{ {
bool is_year_sign_negative = ecma_date_parse_special_char (str_p, str_end_p, '-'); bool is_year_sign_negative = ecma_date_parse_special_char (str_p, str_end_p, LIT_CHAR_MINUS);
const lit_utf8_byte_t *str_start_p = *str_p; const lit_utf8_byte_t *str_start_p = *str_p;
int32_t parsed_year = 0; int32_t parsed_year = 0;
@@ -255,16 +265,18 @@ ecma_date_construct_helper (const ecma_value_t *args, /**< arguments passed to t
* @return the parsed date as ecma_number_t or NaN otherwise * @return the parsed date as ecma_number_t or NaN otherwise
*/ */
static ecma_number_t static ecma_number_t
ecma_builtin_date_parse_ISO_string_format (const lit_utf8_byte_t *date_str_curr_p, ecma_builtin_date_parse_basic (const lit_utf8_byte_t *date_str_curr_p,
const lit_utf8_byte_t *date_str_end_p) const lit_utf8_byte_t *date_str_end_p)
{ {
/* 1. read year */ /* 1. read year */
uint32_t year_digits = 4; uint32_t year_digits = 4;
bool is_year_sign_negative = ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, '-'); bool is_year_sign_negative = false;
if (is_year_sign_negative || ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, '+'))
if (ecma_date_check_two_chars (date_str_curr_p, date_str_end_p, LIT_CHAR_MINUS, LIT_CHAR_PLUS))
{ {
is_year_sign_negative = (*date_str_curr_p++ == LIT_CHAR_MINUS);
year_digits = 6; year_digits = 6;
} }
@@ -282,21 +294,24 @@ ecma_builtin_date_parse_ISO_string_format (const lit_utf8_byte_t *date_str_curr_
ecma_number_t time = ECMA_NUMBER_ZERO; ecma_number_t time = ECMA_NUMBER_ZERO;
/* 2. read month if any */ /* 2. read month if any */
if (ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, '-')) if (ecma_date_check_two_chars (date_str_curr_p, date_str_end_p, LIT_CHAR_MINUS, LIT_CHAR_SLASH))
{ {
lit_utf8_byte_t separator = *date_str_curr_p++;
month = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 1, 12); month = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 1, 12);
}
/* 3. read day if any */ /* 3. read day if any */
if (ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, '-')) if (ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, separator))
{ {
day = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 1, 31); day = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 1, 31);
}
} }
bool is_utc = true; bool is_utc = true;
/* 4. read time if any */ /* 4. read time if any */
if (ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, 'T')) if (ecma_date_check_two_chars (date_str_curr_p, date_str_end_p, LIT_CHAR_UPPERCASE_T, LIT_CHAR_SP))
{ {
date_str_curr_p++;
ecma_number_t hours = ECMA_NUMBER_ZERO; ecma_number_t hours = ECMA_NUMBER_ZERO;
ecma_number_t minutes = ECMA_NUMBER_ZERO; ecma_number_t minutes = ECMA_NUMBER_ZERO;
ecma_number_t seconds = ECMA_NUMBER_ZERO; ecma_number_t seconds = ECMA_NUMBER_ZERO;
@@ -310,17 +325,17 @@ ecma_builtin_date_parse_ISO_string_format (const lit_utf8_byte_t *date_str_curr_
/* 4.1 read hours and minutes */ /* 4.1 read hours and minutes */
hours = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 24); hours = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 24);
if (ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ':')) if (ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_COLON))
{ {
minutes = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 59); minutes = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 59);
/* 4.2 read seconds if any */ /* 4.2 read seconds if any */
if (ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ':')) if (ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_COLON))
{ {
seconds = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 59); seconds = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 59);
/* 4.3 read milliseconds if any */ /* 4.3 read milliseconds if any */
if (ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, '.')) if (ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_DOT))
{ {
milliseconds = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 3, 0, 999); milliseconds = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 3, 0, 999);
} }
@@ -344,17 +359,17 @@ ecma_builtin_date_parse_ISO_string_format (const lit_utf8_byte_t *date_str_curr_
} }
/* 4.4 read timezone if any */ /* 4.4 read timezone if any */
if (ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, 'Z') && !ecma_number_is_nan (time)) if (ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_UPPERCASE_Z)
&& !ecma_number_is_nan (time))
{ {
time = ecma_date_make_time (hours, minutes, seconds, milliseconds); time = ecma_date_make_time (hours, minutes, seconds, milliseconds);
} }
else else
{ {
bool is_timezone_sign_negative; if (lit_utf8_string_length (date_str_curr_p, (lit_utf8_size_t) (date_str_end_p - date_str_curr_p)) == 6
if ((lit_utf8_string_length (date_str_curr_p, (lit_utf8_size_t) (date_str_end_p - date_str_curr_p)) == 6) && ecma_date_check_two_chars (date_str_curr_p, date_str_end_p, LIT_CHAR_MINUS, LIT_CHAR_PLUS))
&& ((is_timezone_sign_negative = ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, '-'))
|| ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, '+')))
{ {
bool is_timezone_sign_negative = (*date_str_curr_p++ == LIT_CHAR_MINUS);
/* read hours and minutes */ /* read hours and minutes */
hours = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 24); hours = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 24);
@@ -363,7 +378,7 @@ ecma_builtin_date_parse_ISO_string_format (const lit_utf8_byte_t *date_str_curr_
hours = ECMA_NUMBER_ZERO; hours = ECMA_NUMBER_ZERO;
} }
ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ':'); ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_COLON);
minutes = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 59); minutes = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 59);
ecma_number_t timezone_offset = ecma_date_make_time (hours, minutes, ECMA_NUMBER_ZERO, ECMA_NUMBER_ZERO); ecma_number_t timezone_offset = ecma_date_make_time (hours, minutes, ECMA_NUMBER_ZERO, ECMA_NUMBER_ZERO);
time += is_timezone_sign_negative ? timezone_offset : -timezone_offset; time += is_timezone_sign_negative ? timezone_offset : -timezone_offset;
@@ -389,7 +404,7 @@ ecma_builtin_date_parse_ISO_string_format (const lit_utf8_byte_t *date_str_curr_
} }
} }
return ecma_number_make_nan (); return ecma_number_make_nan ();
} /* ecma_builtin_date_parse_ISO_string_format */ } /* ecma_builtin_date_parse_basic */
/** /**
* Helper function used by ecma_builtin_date_parse * Helper function used by ecma_builtin_date_parse
@@ -414,9 +429,9 @@ ecma_builtin_date_parse_toString_formats (const lit_utf8_byte_t *date_str_curr_p
return nan; return nan;
} }
const bool is_toUTCString_format = ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ','); const bool is_toUTCString_format = ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_COMMA);
if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ' ')) if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_SP))
{ {
return nan; return nan;
} }
@@ -431,7 +446,7 @@ ecma_builtin_date_parse_toString_formats (const lit_utf8_byte_t *date_str_curr_p
return nan; return nan;
} }
if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ' ')) if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_SP))
{ {
return nan; return nan;
} }
@@ -450,7 +465,7 @@ ecma_builtin_date_parse_toString_formats (const lit_utf8_byte_t *date_str_curr_p
return nan; return nan;
} }
if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ' ')) if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_SP))
{ {
return nan; return nan;
} }
@@ -462,7 +477,7 @@ ecma_builtin_date_parse_toString_formats (const lit_utf8_byte_t *date_str_curr_p
} }
} }
if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ' ')) if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_SP))
{ {
return nan; return nan;
} }
@@ -473,7 +488,7 @@ ecma_builtin_date_parse_toString_formats (const lit_utf8_byte_t *date_str_curr_p
return nan; return nan;
} }
if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ' ')) if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_SP))
{ {
return nan; return nan;
} }
@@ -484,7 +499,7 @@ ecma_builtin_date_parse_toString_formats (const lit_utf8_byte_t *date_str_curr_p
return nan; return nan;
} }
if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ':')) if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_COLON))
{ {
return nan; return nan;
} }
@@ -495,7 +510,7 @@ ecma_builtin_date_parse_toString_formats (const lit_utf8_byte_t *date_str_curr_p
return nan; return nan;
} }
if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ':')) if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_COLON))
{ {
return nan; return nan;
} }
@@ -511,22 +526,22 @@ ecma_builtin_date_parse_toString_formats (const lit_utf8_byte_t *date_str_curr_p
return nan; return nan;
} }
if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ' ')) if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_SP))
{ {
return nan; return nan;
} }
if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, 'G')) if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_UPPERCASE_G))
{ {
return nan; return nan;
} }
if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, 'M')) if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_UPPERCASE_M))
{ {
return nan; return nan;
} }
if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, 'T')) if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_UPPERCASE_T))
{ {
return nan; return nan;
} }
@@ -535,8 +550,8 @@ ecma_builtin_date_parse_toString_formats (const lit_utf8_byte_t *date_str_curr_p
if (!is_toUTCString_format) if (!is_toUTCString_format)
{ {
bool is_timezone_sign_negative = ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, '-'); bool is_timezone_sign_negative = ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_MINUS);
if (!is_timezone_sign_negative && !ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, '+')) if (!is_timezone_sign_negative && !ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_PLUS))
{ {
return nan; return nan;
} }
@@ -599,8 +614,8 @@ ecma_builtin_date_parse (ecma_value_t this_arg, /**< this argument */
const lit_utf8_byte_t *date_str_curr_p = date_start_p; const lit_utf8_byte_t *date_str_curr_p = date_start_p;
const lit_utf8_byte_t *date_str_end_p = date_start_p + date_start_size; const lit_utf8_byte_t *date_str_end_p = date_start_p + date_start_size;
// try to parse date string as ISO string - ECMA-262 v5, 15.9.1.15 // try to parse date string as ISO string and allow some variants - ECMA-262 v5, 15.9.1.15
ecma_number_t ret_value = ecma_builtin_date_parse_ISO_string_format (date_str_curr_p, date_str_end_p); ecma_number_t ret_value = ecma_builtin_date_parse_basic (date_str_curr_p, date_str_end_p);
if (ecma_number_is_nan (ret_value)) if (ecma_number_is_nan (ret_value))
{ {
+5 -1
View File
@@ -40,7 +40,7 @@ var wrongFormats = ["",
"2015-01-01T24:00:01.000", "2015-01-01T24:00:01.000",
"2015-01-01T24:00:00.001", "2015-01-01T24:00:00.001",
"2015-01-01T00:00+01:00Z", "2015-01-01T00:00+01:00Z",
"2015/01/01", "2015/01-01",
"2015-01-32", "2015-01-32",
"2015--1", "2015--1",
"2015-13", "2015-13",
@@ -176,3 +176,7 @@ assert (Date.parse("Fri, 31 Dec 9999 23:59:59 GMT") == 253402300799000)
assert (Date.parse("Sat, 01 Jan 10000 00:00:00 GMT") == 253402300800000) assert (Date.parse("Sat, 01 Jan 10000 00:00:00 GMT") == 253402300800000)
assert (Date.parse("Sat, 13 Sep 275760 00:00:00 GMT") == 8640000000000000) assert (Date.parse("Sat, 13 Sep 275760 00:00:00 GMT") == 8640000000000000)
assert (isNaN(Date.parse("Sat, 13 Sep 275760 00:00:01 GMT"))) // 8640000000001000 - out of range assert (isNaN(Date.parse("Sat, 13 Sep 275760 00:00:01 GMT"))) // 8640000000001000 - out of range
// Non standard date formats
assert (Date.parse("2000/01/01 12:12Z") == 946728720000)
assert (Date.parse("1991-07-13 16:04Z") == 679421040000)