/** * Helper function to make day value from year, month and date. * * See also: * ECMA-262 v5, 15.9.1.12 * * @return day value */ ecma_number_t ecma_date_make_day (ecma_number_t year, /**< year value */ ecma_number_t month, /**< month value */ ecma_number_t date) /**< date value */ { /* 1. */ if (ecma_number_is_nan (year) || ecma_number_is_nan (month) || ecma_number_is_nan (date) || ecma_number_is_infinity (year) || ecma_number_is_infinity (month) || ecma_number_is_infinity (date)) { return ecma_number_make_nan (); } /* 2., 3., 4. */ ecma_number_t y = ecma_number_trunc (year); ecma_number_t m = ecma_number_trunc (month); ecma_number_t dt = ecma_number_trunc (date); /* 5. */ ecma_number_t ym = y + (ecma_number_t) floor (m / 12); /* 6. */ ecma_number_t mn = (ecma_number_t) fmod (m, 12); mn = (mn < 0) ? 12 + mn : mn; /* 7. */ ecma_number_t time = ecma_date_time_from_year (ym); /** * The algorithm below searches the following date: ym-mn-1 * To find this time it starts from the beginning of the year (ym) * then find the first day of the month. */ if (ecma_date_year_from_time (time) == ym) { /* Get the month */ time += 31 * mn * ECMA_DATE_MS_PER_DAY; /* Get the month's first day */ time += ((ecma_number_t) 1.0 - ecma_date_date_from_time (time)) * ECMA_DATE_MS_PER_DAY; if (ecma_date_month_from_time (time) == mn && ecma_date_date_from_time (time) == 1) { /* 8. */ return ecma_date_day (time) + dt - ((ecma_number_t) 1.0); } } return ecma_number_make_nan (); } /* ecma_date_make_day */
/** * The Date object's 'UTC' routine * * See also: * ECMA-262 v5, 15.9.4.3 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_date_utc (ecma_value_t this_arg __attr_unused___, /**< this argument */ const ecma_value_t args[], /**< arguments list */ ecma_length_t args_number) /**< number of arguments */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); if (args_number < 2) { /* Note: * When the UTC function is called with fewer than two arguments, * the behaviour is implementation-dependent, so just return NaN. */ ecma_number_t *nan_p = ecma_alloc_number (); *nan_p = ecma_number_make_nan (); return ecma_make_normal_completion_value (ecma_make_number_value (nan_p)); } ECMA_TRY_CATCH (time_value, ecma_date_construct_helper (args, args_number), ret_value); ecma_number_t *time_p = ecma_get_number_from_value (time_value); ecma_number_t *time_clip_p = ecma_alloc_number (); *time_clip_p = ecma_date_time_clip (*time_p); ret_value = ecma_make_normal_completion_value (ecma_make_number_value (time_clip_p)); ECMA_FINALIZE (time_value); return ret_value; } /* ecma_builtin_date_utc */
/** * Helper function to make time value from hour, min, sec and ms. * * See also: * ECMA-262 v5, 15.9.1.11 * * @return time value */ ecma_number_t ecma_date_make_time (ecma_number_t hour, /**< hour value */ ecma_number_t min, /**< minute value */ ecma_number_t sec, /**< second value */ ecma_number_t ms) /**< millisecond value */ { if (ecma_number_is_nan (hour) || ecma_number_is_nan (min) || ecma_number_is_nan (sec) || ecma_number_is_nan (ms) || ecma_number_is_infinity (hour) || ecma_number_is_infinity (min) || ecma_number_is_infinity (sec) || ecma_number_is_infinity (ms)) { return ecma_number_make_nan (); } /* Replaced toInteger to ecma_number_trunc because it does the same thing. */ ecma_number_t h = ecma_number_trunc (hour); ecma_number_t m = ecma_number_trunc (min); ecma_number_t s = ecma_number_trunc (sec); ecma_number_t milli = ecma_number_trunc (ms); return (h * ECMA_DATE_MS_PER_HOUR + m * ECMA_DATE_MS_PER_MINUTE + s * ECMA_DATE_MS_PER_SECOND + milli); } /* ecma_date_make_time */
/** * The Date object's 'UTC' routine * * See also: * ECMA-262 v5, 15.9.4.3 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_date_utc (ecma_value_t this_arg, /**< this argument */ const ecma_value_t args[], /**< arguments list */ ecma_length_t args_number) /**< number of arguments */ { JERRY_UNUSED (this_arg); ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); if (args_number < 2) { /* Note: * When the UTC function is called with fewer than two arguments, * the behaviour is implementation-dependent, so just return NaN. */ return ecma_make_number_value (ecma_number_make_nan ()); } ECMA_TRY_CATCH (time_value, ecma_date_construct_helper (args, args_number), ret_value); ecma_number_t time = ecma_get_number_from_value (time_value); ret_value = ecma_make_number_value (ecma_date_time_clip (time)); ECMA_FINALIZE (time_value); return ret_value; } /* ecma_builtin_date_utc */
/** * The Date.prototype object's 'setUTCHours' routine * * See also: * ECMA-262 v5, 15.9.5.35 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_date_prototype_set_utc_hours (ecma_value_t this_arg, /**< this argument */ const ecma_value_t args[], /**< arguments list */ ecma_length_t args_number) /**< number of arguments */ { ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); /* 1. */ ECMA_TRY_CATCH (this_time_value, ecma_builtin_date_prototype_get_time (this_arg), ret_value); ecma_number_t t = *ecma_get_number_from_value (this_time_value); /* 2. */ ecma_number_t h = ecma_number_make_nan (); ecma_number_t m = ecma_date_min_from_time (t); ecma_number_t s = ecma_date_sec_from_time (t); ecma_number_t milli = ecma_date_ms_from_time (t); if (args_number > 0 && !ecma_is_value_undefined (args[0])) { ECMA_OP_TO_NUMBER_TRY_CATCH (hour, args[0], ret_value); h = hour; /* 3. */ if (args_number > 1 && !ecma_is_value_undefined (args[1])) { ECMA_OP_TO_NUMBER_TRY_CATCH (min, args[1], ret_value); m = min; /* 4. */ if (args_number > 2 && !ecma_is_value_undefined (args[2])) { ECMA_OP_TO_NUMBER_TRY_CATCH (sec, args[2], ret_value); s = sec; /* 5. */ if (args_number > 3 && !ecma_is_value_undefined (args[3])) { ECMA_OP_TO_NUMBER_TRY_CATCH (ms, args[3], ret_value); milli = ms; ECMA_OP_TO_NUMBER_FINALIZE (ms); } ECMA_OP_TO_NUMBER_FINALIZE (sec); } ECMA_OP_TO_NUMBER_FINALIZE (min); } ECMA_OP_TO_NUMBER_FINALIZE (hour); } if (ecma_is_value_empty (ret_value)) { /* 6-9. */ ret_value = ecma_date_set_internal_property (this_arg, ecma_date_day (t), ecma_date_make_time (h, m, s, milli), ECMA_DATE_UTC); } ECMA_FINALIZE (this_time_value); return ret_value; } /* ecma_builtin_date_prototype_set_utc_hours */
/** * The String.prototype object's 'charCodeAt' routine * * See also: * ECMA-262 v5, 15.5.4.5 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_string_prototype_object_char_code_at (ecma_value_t this_arg, /**< this argument */ ecma_value_t arg) /**< routine's argument */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); /* 1 */ ECMA_TRY_CATCH (check_coercible_val, ecma_op_check_object_coercible (this_arg), ret_value); /* 2 */ ECMA_TRY_CATCH (to_string_val, ecma_op_to_string (this_arg), ret_value); /* 3 */ ECMA_OP_TO_NUMBER_TRY_CATCH (index_num, arg, ret_value); /* 4 */ ecma_string_t *original_string_p = ecma_get_string_from_value (to_string_val); const ecma_length_t len = ecma_string_get_length (original_string_p); ecma_number_t *ret_num_p = ecma_alloc_number (); /* 5 */ // When index_num is NaN, then the first two comparisons are false if (index_num < 0 || index_num >= len || (ecma_number_is_nan (index_num) && !len)) { *ret_num_p = ecma_number_make_nan (); } else { /* 6 */ /* * String length is currently uit32_t, but index_num may be bigger, * ToInteger performs floor, while ToUInt32 performs modulo 2^32, * hence after the check 0 <= index_num < len we assume to_uint32 can be used. * We assume to_uint32 (NaN) is 0. */ JERRY_ASSERT (ecma_number_is_nan (index_num) || ecma_number_to_uint32 (index_num) == ecma_number_trunc (index_num)); ecma_char_t new_ecma_char = ecma_string_get_char_at_pos (original_string_p, ecma_number_to_uint32 (index_num)); *ret_num_p = ecma_uint32_to_number (new_ecma_char); } ecma_value_t new_value = ecma_make_number_value (ret_num_p); ret_value = ecma_make_normal_completion_value (new_value); ECMA_OP_TO_NUMBER_FINALIZE (index_num); ECMA_FINALIZE (to_string_val); ECMA_FINALIZE (check_coercible_val); return ret_value; } /* ecma_builtin_string_prototype_object_char_code_at */
/** * Helper function to make date value from day and time. * * See also: * ECMA-262 v5, 15.9.1.13 * * @return date value */ ecma_number_t ecma_date_make_date (ecma_number_t day, /**< day value */ ecma_number_t time) /**< time value */ { if (ecma_number_is_nan (day) || ecma_number_is_nan (time)) { return ecma_number_make_nan (); } ecma_number_t result = day * ECMA_DATE_MS_PER_DAY + time; if (ecma_number_is_infinity (result)) { return ecma_number_make_nan (); } return result; } /* ecma_date_make_date */
/** * The Date.prototype object's 'setFullYear' routine * * See also: * ECMA-262 v5, 15.9.5.40 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_date_prototype_set_full_year (ecma_value_t this_arg, /**< this argument */ const ecma_value_t args[], /**< arguments list */ ecma_length_t args_number) /**< number of arguments */ { ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); /* 1. */ ECMA_TRY_CATCH (this_time_value, ecma_builtin_date_prototype_get_time (this_arg), ret_value); ecma_number_t t = ecma_date_local_time (*ecma_get_number_from_value (this_time_value)); if (ecma_number_is_nan (t)) { t = ECMA_NUMBER_ZERO; } /* 2. */ ecma_number_t y = ecma_number_make_nan (); ecma_number_t m = ecma_date_month_from_time (t); ecma_number_t dt = ecma_date_date_from_time (t); if (args_number > 0 && !ecma_is_value_undefined (args[0])) { ECMA_OP_TO_NUMBER_TRY_CATCH (year, args[0], ret_value); y = year; /* 3. */ if (args_number > 1 && !ecma_is_value_undefined (args[1])) { ECMA_OP_TO_NUMBER_TRY_CATCH (month, args[1], ret_value); m = month; /* 4. */ if (args_number > 2 && !ecma_is_value_undefined (args[2])) { ECMA_OP_TO_NUMBER_TRY_CATCH (date, args[2], ret_value); dt = date; ECMA_OP_TO_NUMBER_FINALIZE (date); } ECMA_OP_TO_NUMBER_FINALIZE (month); } ECMA_OP_TO_NUMBER_FINALIZE (year); } if (ecma_is_value_empty (ret_value)) { /* 5-8. */ ret_value = ecma_date_set_internal_property (this_arg, ecma_date_make_day (y, m, dt), ecma_date_time_within_day (t), ECMA_DATE_LOCAL); } ECMA_FINALIZE (this_time_value); return ret_value; } /* ecma_builtin_date_prototype_set_full_year */
/** * Helper function to calculate number of milliseconds from time value. * * See also: * ECMA-262 v5, 15.9.1.14 * * @return number of milliseconds */ ecma_number_t ecma_date_time_clip (ecma_number_t time) /**< time value */ { if (ecma_number_is_nan (time) || ecma_number_is_infinity (time) || fabs (time) > ECMA_DATE_MAX_VALUE) { return ecma_number_make_nan (); } return ecma_number_trunc (time); } /* ecma_date_time_clip */
/** * Helper function to get local time from UTC. * * See also: * ECMA-262 v5, 15.9.1.9 * * @return local time */ inline ecma_number_t __attr_always_inline___ ecma_date_local_time_zone (ecma_number_t time) /**< time value */ { jerry_time_zone_t tz; if (ecma_number_is_nan (time) || !jerry_port_get_time_zone (&tz)) { return ecma_number_make_nan (); } return ecma_date_local_tza (&tz) + ecma_date_daylight_saving_ta (&tz, time); } /* ecma_date_local_time_zone */
/** * The Date.prototype object's 'setMinutes' routine * * See also: * ECMA-262 v5, 15.9.5.32 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_date_prototype_set_minutes (ecma_value_t this_arg, /**< this argument */ const ecma_value_t args[], /**< arguments list */ ecma_length_t args_number) /**< number of arguments */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); /* 1. */ ECMA_TRY_CATCH (this_time_value, ecma_builtin_date_prototype_get_time (this_arg), ret_value); ecma_number_t t = ecma_date_local_time (*ecma_get_number_from_value (this_time_value)); /* 2. */ ecma_number_t m = ecma_number_make_nan (); ecma_number_t s = ecma_date_sec_from_time (t); ecma_number_t milli = ecma_date_ms_from_time (t); if (args_number > 0 && !ecma_is_value_undefined (args[0])) { ECMA_OP_TO_NUMBER_TRY_CATCH (min, args[0], ret_value); m = min; /* 3. */ if (args_number > 1 && !ecma_is_value_undefined (args[1])) { ECMA_OP_TO_NUMBER_TRY_CATCH (sec, args[1], ret_value); s = sec; /* 4. */ if (args_number > 2 && !ecma_is_value_undefined (args[2])) { ECMA_OP_TO_NUMBER_TRY_CATCH (ms, args[2], ret_value); milli = ms; ECMA_OP_TO_NUMBER_FINALIZE (ms); } ECMA_OP_TO_NUMBER_FINALIZE (sec); } ECMA_OP_TO_NUMBER_FINALIZE (min); } if (ecma_is_completion_value_empty (ret_value)) { /* 5-8. */ ecma_number_t hour = ecma_date_hour_from_time (t); ret_value = ecma_date_set_internal_property (this_arg, ecma_date_day (t), ecma_date_make_time (hour, m, s, milli), ECMA_DATE_LOCAL); } ECMA_FINALIZE (this_time_value); return ret_value; } /* ecma_builtin_date_prototype_set_minutes */
/** * Helper function to get utc from local time. * * See also: * ECMA-262 v5, 15.9.1.9 * * @return utc time */ ecma_number_t ecma_date_utc (ecma_number_t time) /**< time value */ { jerry_time_zone_t tz; if (ecma_number_is_nan (time) || !jerry_port_get_time_zone (&tz)) { return ecma_number_make_nan (); } ecma_number_t simple_utc_time = time - ecma_date_local_tza (&tz); return simple_utc_time - ecma_date_daylight_saving_ta (&tz, simple_utc_time); } /* ecma_date_utc */
/** * The Date.prototype object's 'setYear' routine * * See also: * ECMA-262 v5, AnnexB.B.2.5 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_date_prototype_set_year (ecma_value_t this_arg, /**< this argument */ ecma_value_t year) /**< year argument */ { ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); /* 1. */ ECMA_TRY_CATCH (this_time_value, ecma_builtin_date_prototype_get_time (this_arg), ret_value); ecma_number_t t = ecma_date_local_time (*ecma_get_number_from_value (this_time_value)); if (ecma_number_is_nan (t)) { t = ECMA_NUMBER_ZERO; } /* 2. */ ecma_number_t y = ecma_number_make_nan (); ECMA_OP_TO_NUMBER_TRY_CATCH (year_value, year, ret_value); y = year_value; /* 3. */ if (ecma_number_is_nan (y)) { ret_value = ecma_date_set_internal_property (this_arg, 0, y, ECMA_DATE_UTC); } else { /* 4. */ if (y >= 0 && y <= 99) { y += 1900; } } ECMA_OP_TO_NUMBER_FINALIZE (year_value); if (ecma_is_value_empty (ret_value)) { /* 5-8. */ ecma_number_t m = ecma_date_month_from_time (t); ecma_number_t dt = ecma_date_date_from_time (t); ret_value = ecma_date_set_internal_property (this_arg, ecma_date_make_day (y, m, dt), ecma_date_time_within_day (t), ECMA_DATE_UTC); } ECMA_FINALIZE (this_time_value); return ret_value; } /* ecma_builtin_date_prototype_set_year */
/** * Helper function to try to parse a part of a date string * * @return NaN if cannot read from string, ToNumber() otherwise */ static ecma_number_t ecma_date_parse_date_chars (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 */ uint32_t num_of_chars) /**< number of characters to read and convert */ { JERRY_ASSERT (num_of_chars > 0); const lit_utf8_byte_t *str_start_p = *str_p; while (num_of_chars--) { if (*str_p >= str_end_p || !lit_char_is_decimal_digit (lit_utf8_read_next (str_p))) { return ecma_number_make_nan (); } } return ecma_utf8_string_to_number (str_start_p, (lit_utf8_size_t) (*str_p - str_start_p)); } /* ecma_date_parse_date_chars */
/** * Helper function to try to parse a part of a date string * * @return NaN if cannot read from string, ToNumber() otherwise */ static ecma_number_t ecma_date_parse_date_chars (lit_utf8_iterator_t *iter, /**< iterator of the utf8 string */ uint32_t num_of_chars) /**< number of characters to read and convert */ { JERRY_ASSERT (num_of_chars > 0); lit_utf8_size_t copy_size = 0; const lit_utf8_byte_t *str_start_p = iter->buf_p + iter->buf_pos.offset; while (num_of_chars--) { if (lit_utf8_iterator_is_eos (iter) || !lit_char_is_unicode_digit (lit_utf8_iterator_peek_next (iter))) { return ecma_number_make_nan (); } copy_size += lit_get_unicode_char_size_by_utf8_first_byte (*(iter->buf_p + iter->buf_pos.offset)); lit_utf8_iterator_incr (iter); } return ecma_utf8_string_to_number (str_start_p, copy_size); } /* ecma_date_parse_date_chars */
/** * Initialize specified built-in object. * * @return pointer to the object */ static ecma_object_t * ecma_builtin_init_object (ecma_builtin_id_t obj_builtin_id, /**< built-in ID */ ecma_object_t *prototype_obj_p, /**< prototype object */ ecma_object_type_t obj_type, /**< object's type */ bool is_extensible) /**< value of object's [[Extensible]] property */ { ecma_object_t *obj_p = ecma_create_object (prototype_obj_p, true, is_extensible, obj_type); /* * [[Class]] property of built-in object is not stored explicitly. * * See also: ecma_object_get_class_name */ ecma_set_object_is_builtin (obj_p); ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p; ext_obj_p->u.built_in.id = obj_builtin_id; ext_obj_p->u.built_in.routine_id = obj_builtin_id; ext_obj_p->u.built_in.instantiated_bitset = 0; /** Initializing [[PrimitiveValue]] properties of built-in prototype objects */ switch (obj_builtin_id) { #ifndef CONFIG_DISABLE_ARRAY_BUILTIN case ECMA_BUILTIN_ID_ARRAY_PROTOTYPE: { ecma_string_t *length_str_p = ecma_new_ecma_length_string (); ecma_property_t *length_prop_p = ecma_create_named_data_property (obj_p, length_str_p, ECMA_PROPERTY_FLAG_WRITABLE); ecma_set_named_data_property_value (length_prop_p, ecma_make_integer_value (0)); ecma_deref_ecma_string (length_str_p); break; } #endif /* !CONFIG_DISABLE_ARRAY_BUILTIN */ #ifndef CONFIG_DISABLE_STRING_BUILTIN case ECMA_BUILTIN_ID_STRING_PROTOTYPE: { ecma_string_t *prim_prop_str_value_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); ecma_value_t *prim_value_p = ecma_create_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_ECMA_VALUE); *prim_value_p = ecma_make_string_value (prim_prop_str_value_p); break; } #endif /* !CONFIG_DISABLE_STRING_BUILTIN */ #ifndef CONFIG_DISABLE_NUMBER_BUILTIN case ECMA_BUILTIN_ID_NUMBER_PROTOTYPE: { ecma_value_t *prim_value_p = ecma_create_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_ECMA_VALUE); *prim_value_p = ecma_make_integer_value (0); break; } #endif /* !CONFIG_DISABLE_NUMBER_BUILTIN */ #ifndef CONFIG_DISABLE_BOOLEAN_BUILTIN case ECMA_BUILTIN_ID_BOOLEAN_PROTOTYPE: { ecma_value_t *prim_value_p = ecma_create_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_ECMA_VALUE); *prim_value_p = ecma_make_simple_value (ECMA_SIMPLE_VALUE_FALSE); break; } #endif /* !CONFIG_DISABLE_BOOLEAN_BUILTIN */ #ifndef CONFIG_DISABLE_DATE_BUILTIN case ECMA_BUILTIN_ID_DATE_PROTOTYPE: { ecma_number_t *prim_prop_num_value_p = ecma_alloc_number (); *prim_prop_num_value_p = ecma_number_make_nan (); ecma_value_t *prim_value_p = ecma_create_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_DATE_FLOAT); ECMA_SET_INTERNAL_VALUE_POINTER (*prim_value_p, prim_prop_num_value_p); break; } #endif /* !CONFIG_DISABLE_DATE_BUILTIN */ #ifndef CONFIG_DISABLE_REGEXP_BUILTIN case ECMA_BUILTIN_ID_REGEXP_PROTOTYPE: { ecma_value_t *bytecode_prop_p = ecma_create_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE); *bytecode_prop_p = ECMA_NULL_POINTER; break; } #endif /* !CONFIG_DISABLE_REGEXP_BUILTIN */ default: { break; } } return obj_p; } /* ecma_builtin_init_object */
/** * If the property's name is one of built-in properties of the object * that is not instantiated yet, instantiate the property and * return pointer to the instantiated property. * * @return pointer property, if one was instantiated, * NULL - otherwise. */ ecma_property_t * ecma_builtin_try_to_instantiate_property (ecma_object_t *object_p, /**< object */ ecma_string_t *string_p) /**< property's name */ { JERRY_ASSERT (ecma_get_object_is_builtin (object_p)); ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p; if (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_FUNCTION && ecma_builtin_function_is_routine (object_p)) { if (ecma_string_is_length (string_p)) { /* * Lazy instantiation of 'length' property * * Note: * We don't need to mark that the property was already lazy instantiated, * as it is non-configurable and so can't be deleted */ ecma_property_t *len_prop_p = ecma_create_named_data_property (object_p, string_p, ECMA_PROPERTY_FIXED); ecma_set_named_data_property_value (len_prop_p, ecma_make_integer_value (ext_obj_p->u.built_in.length)); JERRY_ASSERT (!ecma_is_property_configurable (len_prop_p)); return len_prop_p; } return NULL; } lit_magic_string_id_t magic_string_id; if (!ecma_is_string_magic (string_p, &magic_string_id)) { return NULL; } ecma_builtin_id_t builtin_id = (ecma_builtin_id_t) ext_obj_p->u.built_in.id; JERRY_ASSERT (builtin_id < ECMA_BUILTIN_ID__COUNT); JERRY_ASSERT (ecma_builtin_is (object_p, builtin_id)); const ecma_builtin_property_descriptor_t *property_list_p = ecma_builtin_property_list_references[builtin_id]; const ecma_builtin_property_descriptor_t *curr_property_p = property_list_p; while (curr_property_p->magic_string_id != magic_string_id) { if (curr_property_p->magic_string_id == LIT_MAGIC_STRING__COUNT) { return NULL; } curr_property_p++; } uint32_t index = (uint32_t) (curr_property_p - property_list_p); JERRY_ASSERT (index < 64); if (likely (index < 32)) { uint32_t bit_for_index = (uint32_t) 1u << index; if (ext_obj_p->u.built_in.instantiated_bitset & bit_for_index) { /* This property was instantiated before. */ return NULL; } ext_obj_p->u.built_in.instantiated_bitset |= bit_for_index; } else { uint32_t bit_for_index = (uint32_t) 1u << (index - 32); ecma_value_t *mask_prop_p = ecma_find_internal_property (object_p, ECMA_INTERNAL_PROPERTY_INSTANTIATED_MASK_32_63); uint32_t instantiated_bitset; if (mask_prop_p == NULL) { mask_prop_p = ecma_create_internal_property (object_p, ECMA_INTERNAL_PROPERTY_INSTANTIATED_MASK_32_63); instantiated_bitset = 0; } else { instantiated_bitset = *mask_prop_p; if (instantiated_bitset & bit_for_index) { /* This property was instantiated before. */ return NULL; } } *mask_prop_p = (instantiated_bitset | bit_for_index); } ecma_value_t value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); switch (curr_property_p->type) { case ECMA_BUILTIN_PROPERTY_SIMPLE: { value = ecma_make_simple_value (curr_property_p->value); break; } case ECMA_BUILTIN_PROPERTY_NUMBER: { ecma_number_t num = 0.0; if (curr_property_p->value < ECMA_BUILTIN_NUMBER_MAX) { num = curr_property_p->value; } else if (curr_property_p->value < ECMA_BUILTIN_NUMBER_NAN) { static const ecma_number_t builtin_number_list[] = { ECMA_NUMBER_MAX_VALUE, ECMA_NUMBER_MIN_VALUE, ECMA_NUMBER_E, ECMA_NUMBER_PI, ECMA_NUMBER_LN10, ECMA_NUMBER_LN2, ECMA_NUMBER_LOG2E, ECMA_NUMBER_LOG10E, ECMA_NUMBER_SQRT2, ECMA_NUMBER_SQRT_1_2 }; num = builtin_number_list[curr_property_p->value - ECMA_BUILTIN_NUMBER_MAX]; } else { switch (curr_property_p->value) { case ECMA_BUILTIN_NUMBER_NAN: { num = ecma_number_make_nan (); break; } case ECMA_BUILTIN_NUMBER_POSITIVE_INFINITY: { num = ecma_number_make_infinity (false); break; } case ECMA_BUILTIN_NUMBER_NEGATIVE_INFINITY: { num = ecma_number_make_infinity (true); break; } default: { JERRY_UNREACHABLE (); break; } } } value = ecma_make_number_value (num); break; } case ECMA_BUILTIN_PROPERTY_STRING: { value = ecma_make_string_value (ecma_get_magic_string (curr_property_p->value)); break; } case ECMA_BUILTIN_PROPERTY_OBJECT: { value = ecma_make_object_value (ecma_builtin_get (curr_property_p->value)); break; } case ECMA_BUILTIN_PROPERTY_ROUTINE: { ecma_object_t *func_obj_p; func_obj_p = ecma_builtin_make_function_object_for_routine (builtin_id, ECMA_GET_ROUTINE_ID (curr_property_p->value), ECMA_GET_ROUTINE_LENGTH (curr_property_p->value)); value = ecma_make_object_value (func_obj_p); break; } default: { JERRY_UNREACHABLE (); return NULL; } } ecma_property_t *prop_p = ecma_create_named_data_property (object_p, string_p, curr_property_p->attributes); ecma_set_named_data_property_value (prop_p, value); /* Reference count of objects must be decreased. */ if (ecma_is_value_object (value)) { ecma_free_value (value); } return prop_p; } /* ecma_builtin_try_to_instantiate_property */
/** * Initialize specified built-in object. * * Warning: * the routine should be called only from ecma_init_builtins * * @return pointer to the object */ static ecma_object_t * ecma_builtin_init_object (ecma_builtin_id_t obj_builtin_id, /**< built-in ID */ ecma_object_t *prototype_obj_p, /**< prototype object */ ecma_object_type_t obj_type, /**< object's type */ bool is_extensible) /**< value of object's [[Extensible]] property */ { ecma_object_t *object_obj_p = ecma_create_object (prototype_obj_p, is_extensible, obj_type); /* * [[Class]] property of built-in object is not stored explicitly. * * See also: ecma_object_get_class_name */ ecma_property_t *built_in_id_prop_p = ecma_create_internal_property (object_obj_p, ECMA_INTERNAL_PROPERTY_BUILT_IN_ID); built_in_id_prop_p->u.internal_property.value = obj_builtin_id; ecma_set_object_is_builtin (object_obj_p, true); /** Initializing [[PrimitiveValue]] properties of built-in prototype objects */ switch (obj_builtin_id) { #ifndef CONFIG_ECMA_COMPACT_PROFILE_DISABLE_STRING_BUILTIN case ECMA_BUILTIN_ID_STRING_PROTOTYPE: { ecma_string_t *prim_prop_str_value_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); ecma_property_t *prim_value_prop_p; prim_value_prop_p = ecma_create_internal_property (object_obj_p, ECMA_INTERNAL_PROPERTY_PRIMITIVE_STRING_VALUE); ECMA_SET_POINTER (prim_value_prop_p->u.internal_property.value, prim_prop_str_value_p); break; } #endif /* !CONFIG_ECMA_COMPACT_PROFILE_DISABLE_STRING_BUILTIN */ #ifndef CONFIG_ECMA_COMPACT_PROFILE_DISABLE_NUMBER_BUILTIN case ECMA_BUILTIN_ID_NUMBER_PROTOTYPE: { ecma_number_t *prim_prop_num_value_p = ecma_alloc_number (); *prim_prop_num_value_p = ECMA_NUMBER_ZERO; ecma_property_t *prim_value_prop_p; prim_value_prop_p = ecma_create_internal_property (object_obj_p, ECMA_INTERNAL_PROPERTY_PRIMITIVE_NUMBER_VALUE); ECMA_SET_POINTER (prim_value_prop_p->u.internal_property.value, prim_prop_num_value_p); break; } #endif /* !CONFIG_ECMA_COMPACT_PROFILE_DISABLE_NUMBER_BUILTIN */ #ifndef CONFIG_ECMA_COMPACT_PROFILE_DISABLE_BOOLEAN_BUILTIN case ECMA_BUILTIN_ID_BOOLEAN_PROTOTYPE: { ecma_property_t *prim_value_prop_p; prim_value_prop_p = ecma_create_internal_property (object_obj_p, ECMA_INTERNAL_PROPERTY_PRIMITIVE_BOOLEAN_VALUE); prim_value_prop_p->u.internal_property.value = ECMA_SIMPLE_VALUE_FALSE; break; } #endif /* !CONFIG_ECMA_COMPACT_PROFILE_DISABLE_BOOLEAN_BUILTIN */ #ifndef CONFIG_ECMA_COMPACT_PROFILE_DISABLE_DATE_BUILTIN case ECMA_BUILTIN_ID_DATE_PROTOTYPE: { ecma_number_t *prim_prop_num_value_p = ecma_alloc_number (); *prim_prop_num_value_p = ecma_number_make_nan (); ecma_property_t *prim_value_prop_p; prim_value_prop_p = ecma_create_internal_property (object_obj_p, ECMA_INTERNAL_PROPERTY_PRIMITIVE_NUMBER_VALUE); ECMA_SET_POINTER (prim_value_prop_p->u.internal_property.value, prim_prop_num_value_p); break; } #endif /* !CONFIG_ECMA_COMPACT_PROFILE_DISABLE_DATE_BUILTIN */ #ifndef CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN case ECMA_BUILTIN_ID_REGEXP_PROTOTYPE: { ecma_property_t *bytecode_prop_p; bytecode_prop_p = ecma_create_internal_property (object_obj_p, ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE); bytecode_prop_p->u.internal_property.value = ECMA_NULL_POINTER; break; } #endif /* !CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN */ default: { break; } } return object_obj_p; } /* ecma_builtin_init_object */
/** * Calculate MakeDate(MakeDay(yr, m, dt), MakeTime(h, min, s, milli)) for Date constructor and UTC * * See also: * ECMA-262 v5, 15.9.3.1 * ECMA-262 v5, 15.9.4.3 * * @return result of MakeDate(MakeDay(yr, m, dt), MakeTime(h, min, s, milli)) */ static ecma_completion_value_t ecma_date_construct_helper (const ecma_value_t *args, /**< arguments passed to the Date constructor */ ecma_length_t args_len) /**< number of arguments */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); ecma_number_t *prim_value_p = ecma_alloc_number (); *prim_value_p = ecma_number_make_nan (); ECMA_TRY_CATCH (year_value, ecma_op_to_number (args[0]), ret_value); ECMA_TRY_CATCH (month_value, ecma_op_to_number (args[1]), ret_value); ecma_number_t year = *ecma_get_number_from_value (year_value); ecma_number_t month = *ecma_get_number_from_value (month_value); ecma_number_t date = ECMA_NUMBER_ONE; ecma_number_t hours = ECMA_NUMBER_ZERO; ecma_number_t minutes = ECMA_NUMBER_ZERO; ecma_number_t seconds = ECMA_NUMBER_ZERO; ecma_number_t milliseconds = ECMA_NUMBER_ZERO; /* 3. */ if (args_len >= 3 && ecma_is_completion_value_empty (ret_value)) { ECMA_TRY_CATCH (date_value, ecma_op_to_number (args[2]), ret_value); date = *ecma_get_number_from_value (date_value); ECMA_FINALIZE (date_value); } /* 4. */ if (args_len >= 4 && ecma_is_completion_value_empty (ret_value)) { ECMA_TRY_CATCH (hours_value, ecma_op_to_number (args[3]), ret_value); hours = *ecma_get_number_from_value (hours_value); ECMA_FINALIZE (hours_value); } /* 5. */ if (args_len >= 5 && ecma_is_completion_value_empty (ret_value)) { ECMA_TRY_CATCH (minutes_value, ecma_op_to_number (args[4]), ret_value); minutes = *ecma_get_number_from_value (minutes_value); ECMA_FINALIZE (minutes_value); } /* 6. */ if (args_len >= 6 && ecma_is_completion_value_empty (ret_value)) { ECMA_TRY_CATCH (seconds_value, ecma_op_to_number (args[5]), ret_value); seconds = *ecma_get_number_from_value (seconds_value); ECMA_FINALIZE (seconds_value); } /* 7. */ if (args_len >= 7 && ecma_is_completion_value_empty (ret_value)) { ECMA_TRY_CATCH (milliseconds_value, ecma_op_to_number (args[6]), ret_value); milliseconds = *ecma_get_number_from_value (milliseconds_value); ECMA_FINALIZE (milliseconds_value); } if (ecma_is_completion_value_empty (ret_value)) { if (!ecma_number_is_nan (year) && !ecma_number_is_infinity (year)) { /* 8. */ int32_t y = ecma_number_to_int32 (year); if (y >= 0 && y <= 99) { year = (ecma_number_t) (1900 + y); } else { year = (ecma_number_t) y; } } *prim_value_p = ecma_date_make_date (ecma_date_make_day (year, month, date), ecma_date_make_time (hours, minutes, seconds, milliseconds)); } ECMA_FINALIZE (month_value); ECMA_FINALIZE (year_value); if (ecma_is_completion_value_empty (ret_value)) { ret_value = ecma_make_normal_completion_value (ecma_make_number_value (prim_value_p)); } else { ecma_dealloc_number (prim_value_p); } return ret_value; } /* ecma_date_construct_helper */
/** * The Date object's 'parse' routine * * See also: * ECMA-262 v5, 15.9.4.2 * ECMA-262 v5, 15.9.1.15 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_date_parse (ecma_value_t this_arg __attr_unused___, /**< this argument */ ecma_value_t arg) /**< string */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); ecma_number_t *date_num_p = ecma_alloc_number (); *date_num_p = ecma_number_make_nan (); /* Date Time String fromat (ECMA-262 v5, 15.9.1.15) */ ECMA_TRY_CATCH (date_str_value, ecma_op_to_string (arg), ret_value); ecma_string_t *date_str_p = ecma_get_string_from_value (date_str_value); lit_utf8_size_t date_str_size = ecma_string_get_size (date_str_p); MEM_DEFINE_LOCAL_ARRAY (date_start_p, date_str_size, lit_utf8_byte_t); ecma_string_to_utf8_string (date_str_p, date_start_p, (ssize_t) date_str_size); lit_utf8_iterator_t iter = lit_utf8_iterator_create (date_start_p, date_str_size); /* 1. read year */ ecma_number_t year = ecma_date_parse_date_chars (&iter, 4); if (!ecma_number_is_nan (year) && year >= 0) { ecma_number_t month = ECMA_NUMBER_ONE; ecma_number_t day = ECMA_NUMBER_ONE; ecma_number_t time = ECMA_NUMBER_ZERO; /* 2. read month if any */ if (!lit_utf8_iterator_is_eos (&iter) && lit_utf8_iterator_peek_next (&iter) == '-') { /* eat up '-' */ lit_utf8_iterator_incr (&iter); month = ecma_date_parse_date_chars (&iter, 2); if (month > 12 || month < 1) { month = ecma_number_make_nan (); } } /* 3. read day if any */ if (!lit_utf8_iterator_is_eos (&iter) && lit_utf8_iterator_peek_next (&iter) == '-') { /* eat up '-' */ lit_utf8_iterator_incr (&iter); day = ecma_date_parse_date_chars (&iter, 2); if (day < 1 || day > 31) { day = ecma_number_make_nan (); } } /* 4. read time if any */ if (!lit_utf8_iterator_is_eos (&iter) && lit_utf8_iterator_peek_next (&iter) == 'T') { ecma_number_t hours = ECMA_NUMBER_ZERO; ecma_number_t minutes = ECMA_NUMBER_ZERO; ecma_number_t seconds = ECMA_NUMBER_ZERO; ecma_number_t milliseconds = ECMA_NUMBER_ZERO; ecma_length_t num_of_visited_chars = lit_utf8_iterator_get_index (&iter); ecma_length_t date_str_len = lit_utf8_string_length (iter.buf_p, iter.buf_size) - 1; if ((date_str_len - num_of_visited_chars) >= 5) { /* eat up 'T' */ lit_utf8_iterator_incr (&iter); /* 4.1 read hours and minutes */ hours = ecma_date_parse_date_chars (&iter, 2); if (hours < 0 || hours > 24) { hours = ecma_number_make_nan (); } else if (hours == 24) { hours = ECMA_NUMBER_ZERO; } /* eat up ':' */ lit_utf8_iterator_incr (&iter); minutes = ecma_date_parse_date_chars (&iter, 2); if (minutes < 0 || minutes > 59) { minutes = ecma_number_make_nan (); } /* 4.2 read seconds if any */ if (!lit_utf8_iterator_is_eos (&iter) && lit_utf8_iterator_peek_next (&iter) == ':') { /* eat up ':' */ lit_utf8_iterator_incr (&iter); seconds = ecma_date_parse_date_chars (&iter, 2); if (seconds < 0 || seconds > 59) { seconds = ecma_number_make_nan (); } /* 4.3 read milliseconds if any */ if (!lit_utf8_iterator_is_eos (&iter) && lit_utf8_iterator_peek_next (&iter) == '.') { /* eat up '.' */ lit_utf8_iterator_incr (&iter); milliseconds = ecma_date_parse_date_chars (&iter, 3); if (milliseconds < 0) { milliseconds = ecma_number_make_nan (); } } } time = ecma_date_make_time (hours, minutes, seconds, milliseconds); } else { time = ecma_number_make_nan (); } /* 4.4 read timezone if any */ if (!lit_utf8_iterator_is_eos (&iter) && lit_utf8_iterator_peek_next (&iter) == 'Z' && !ecma_number_is_nan (time)) { lit_utf8_iterator_incr (&iter); time = ecma_date_utc (ecma_date_make_time (hours, minutes, seconds, milliseconds)); } else if (!lit_utf8_iterator_is_eos (&iter) && (lit_utf8_iterator_peek_next (&iter) == '+' || lit_utf8_iterator_peek_next (&iter) == '-')) { ecma_length_t num_of_visited_chars = lit_utf8_iterator_get_index (&iter); ecma_length_t date_str_len = lit_utf8_string_length (iter.buf_p, iter.buf_size) - 1; if ((date_str_len - num_of_visited_chars) == 5) { bool is_negative = false; if (lit_utf8_iterator_peek_next (&iter) == '-') { is_negative = true; } /* eat up '+/-' */ lit_utf8_iterator_incr (&iter); /* read hours and minutes */ hours = ecma_date_parse_date_chars (&iter, 2); if (hours < 0 || hours > 24) { hours = ecma_number_make_nan (); } else if (hours == 24) { hours = ECMA_NUMBER_ZERO; } /* eat up ':' */ lit_utf8_iterator_incr (&iter); minutes = ecma_date_parse_date_chars (&iter, 2); if (minutes < 0 || minutes > 59) { minutes = ecma_number_make_nan (); } if (is_negative) { time += ecma_date_make_time (hours, minutes, ECMA_NUMBER_ZERO, ECMA_NUMBER_ZERO); } else { time -= ecma_date_make_time (hours, minutes, ECMA_NUMBER_ZERO, ECMA_NUMBER_ZERO); } } } } if (lit_utf8_iterator_is_eos (&iter)) { ecma_number_t date = ecma_date_make_day (year, month - 1, day); *date_num_p = ecma_date_make_date (date, time); } } ret_value = ecma_make_normal_completion_value (ecma_make_number_value (date_num_p)); MEM_FINALIZE_LOCAL_ARRAY (date_start_p); ECMA_FINALIZE (date_str_value); return ret_value; } /* ecma_builtin_date_parse */
/** * ToNumber operation. * * See also: * ECMA-262 v5, 9.3 * * @return completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t ecma_op_to_number (ecma_value_t value) /**< ecma-value */ { ecma_check_value_type_is_spec_defined (value); if (ecma_is_value_number (value)) { return ecma_make_normal_completion_value (ecma_copy_value (value, true)); } else if (ecma_is_value_string (value)) { ecma_string_t *str_p = ecma_get_string_from_value (value); ecma_number_t *num_p = ecma_alloc_number (); *num_p = ecma_string_to_number (str_p); return ecma_make_normal_completion_value (ecma_make_number_value (num_p)); } else if (ecma_is_value_object (value)) { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); ECMA_TRY_CATCH (primitive_value, ecma_op_to_primitive (value, ECMA_PREFERRED_TYPE_NUMBER), ret_value); ret_value = ecma_op_to_number (primitive_value); ECMA_FINALIZE (primitive_value); return ret_value; } else { ecma_number_t *num_p = ecma_alloc_number (); if (ecma_is_value_undefined (value)) { *num_p = ecma_number_make_nan (); } else if (ecma_is_value_null (value)) { *num_p = ECMA_NUMBER_ZERO; } else { JERRY_ASSERT (ecma_is_value_boolean (value)); if (ecma_is_value_true (value)) { *num_p = ECMA_NUMBER_ONE; } else { *num_p = ECMA_NUMBER_ZERO; } } return ecma_make_normal_completion_value (ecma_make_number_value (num_p)); } } /* ecma_op_to_number */
/** * Calculate MakeDate(MakeDay(yr, m, dt), MakeTime(h, min, s, milli)) for Date constructor and UTC * * See also: * ECMA-262 v5, 15.9.3.1 * ECMA-262 v5, 15.9.4.3 * * @return result of MakeDate(MakeDay(yr, m, dt), MakeTime(h, min, s, milli)) */ static ecma_value_t ecma_date_construct_helper (const ecma_value_t *args, /**< arguments passed to the Date constructor */ ecma_length_t args_len) /**< number of arguments */ { ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); ecma_number_t prim_value = ecma_number_make_nan (); ECMA_TRY_CATCH (year_value, ecma_op_to_number (args[0]), ret_value); ECMA_TRY_CATCH (month_value, ecma_op_to_number (args[1]), ret_value); ecma_number_t year = ecma_get_number_from_value (year_value); ecma_number_t month = ecma_get_number_from_value (month_value); ecma_number_t date = ECMA_NUMBER_ONE; ecma_number_t hours = ECMA_NUMBER_ZERO; ecma_number_t minutes = ECMA_NUMBER_ZERO; ecma_number_t seconds = ECMA_NUMBER_ZERO; ecma_number_t milliseconds = ECMA_NUMBER_ZERO; /* 3. */ if (args_len >= 3 && ecma_is_value_empty (ret_value)) { ECMA_TRY_CATCH (date_value, ecma_op_to_number (args[2]), ret_value); date = ecma_get_number_from_value (date_value); ECMA_FINALIZE (date_value); } /* 4. */ if (args_len >= 4 && ecma_is_value_empty (ret_value)) { ECMA_TRY_CATCH (hours_value, ecma_op_to_number (args[3]), ret_value); hours = ecma_get_number_from_value (hours_value); ECMA_FINALIZE (hours_value); } /* 5. */ if (args_len >= 5 && ecma_is_value_empty (ret_value)) { ECMA_TRY_CATCH (minutes_value, ecma_op_to_number (args[4]), ret_value); minutes = ecma_get_number_from_value (minutes_value); ECMA_FINALIZE (minutes_value); } /* 6. */ if (args_len >= 6 && ecma_is_value_empty (ret_value)) { ECMA_TRY_CATCH (seconds_value, ecma_op_to_number (args[5]), ret_value); seconds = ecma_get_number_from_value (seconds_value); ECMA_FINALIZE (seconds_value); } /* 7. */ if (args_len >= 7 && ecma_is_value_empty (ret_value)) { ECMA_TRY_CATCH (milliseconds_value, ecma_op_to_number (args[6]), ret_value); milliseconds = ecma_get_number_from_value (milliseconds_value); ECMA_FINALIZE (milliseconds_value); } if (ecma_is_value_empty (ret_value)) { if (!ecma_number_is_nan (year)) { /* 8. */ ecma_number_t y = ecma_number_trunc (year); if (y >= 0 && y <= 99) { year = 1900 + y; } } prim_value = ecma_date_make_date (ecma_date_make_day (year, month, date), ecma_date_make_time (hours, minutes, seconds, milliseconds)); } ECMA_FINALIZE (month_value); ECMA_FINALIZE (year_value); if (ecma_is_value_empty (ret_value)) { ret_value = ecma_make_number_value (prim_value); } return ret_value; } /* ecma_date_construct_helper */
/** * Dispatch set date functions * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_date_prototype_dispatch_set (uint16_t builtin_routine_id, /**< built-in wide routine * identifier */ ecma_extended_object_t *ext_object_p, /**< date extended object */ ecma_number_t date_num, /**< date converted to number */ const ecma_value_t arguments_list[], /**< list of arguments * passed to routine */ ecma_length_t arguments_number) /**< length of arguments' list */ { ecma_number_t converted_number[4]; ecma_length_t conversions = 0; /* If the first argument is not specified, it is always converted to NaN. */ converted_number[0] = ecma_number_make_nan (); switch (builtin_routine_id) { #ifndef CONFIG_DISABLE_ANNEXB_BUILTIN case ECMA_DATE_PROTOTYPE_SET_YEAR: #endif /* !CONFIG_DISABLE_ANNEXB_BUILTIN */ case ECMA_DATE_PROTOTYPE_SET_DATE: case ECMA_DATE_PROTOTYPE_SET_UTC_DATE: case ECMA_DATE_PROTOTYPE_SET_UTC_MILLISECONDS: case ECMA_DATE_PROTOTYPE_SET_MILLISECONDS: { conversions = 1; break; } case ECMA_DATE_PROTOTYPE_SET_MONTH: case ECMA_DATE_PROTOTYPE_SET_UTC_MONTH: case ECMA_DATE_PROTOTYPE_SET_UTC_SECONDS: case ECMA_DATE_PROTOTYPE_SET_SECONDS: { conversions = 2; break; } case ECMA_DATE_PROTOTYPE_SET_FULL_YEAR: case ECMA_DATE_PROTOTYPE_SET_UTC_FULL_YEAR: case ECMA_DATE_PROTOTYPE_SET_MINUTES: case ECMA_DATE_PROTOTYPE_SET_UTC_MINUTES: { conversions = 3; break; } default: { JERRY_ASSERT (builtin_routine_id == ECMA_DATE_PROTOTYPE_SET_HOURS || builtin_routine_id == ECMA_DATE_PROTOTYPE_SET_UTC_HOURS); conversions = 4; break; } } if (conversions > arguments_number) { conversions = arguments_number; } for (ecma_length_t i = 0; i < conversions; i++) { ecma_value_t value = ecma_op_to_number (arguments_list[i]); if (ECMA_IS_VALUE_ERROR (value)) { return value; } converted_number[i] = ecma_get_number_from_value (value); ecma_free_value (value); } ecma_number_t day_part; ecma_number_t time_part; if (builtin_routine_id <= ECMA_DATE_PROTOTYPE_SET_UTC_DATE) { if (ecma_number_is_nan (date_num)) { if (ECMA_DATE_PROTOTYPE_IS_SET_YEAR_ROUTINE (builtin_routine_id)) { date_num = ECMA_NUMBER_ZERO; } else { return ecma_make_number_value (date_num); } } time_part = ecma_date_time_within_day (date_num); ecma_number_t year = ecma_date_year_from_time (date_num); ecma_number_t month = ecma_date_month_from_time (date_num); ecma_number_t day = ecma_date_date_from_time (date_num); switch (builtin_routine_id) { case ECMA_DATE_PROTOTYPE_SET_FULL_YEAR: case ECMA_DATE_PROTOTYPE_SET_UTC_FULL_YEAR: { year = converted_number[0]; if (conversions >= 2) { month = converted_number[1]; } if (conversions >= 3) { day = converted_number[2]; } break; } #ifndef CONFIG_DISABLE_ANNEXB_BUILTIN case ECMA_DATE_PROTOTYPE_SET_YEAR: { year = converted_number[0]; if (year >= 0 && year <= 99) { year += 1900; } break; } #endif /* !CONFIG_DISABLE_ANNEXB_BUILTIN */ case ECMA_DATE_PROTOTYPE_SET_MONTH: case ECMA_DATE_PROTOTYPE_SET_UTC_MONTH: { month = converted_number[0]; if (conversions >= 2) { day = converted_number[1]; } break; } default: { JERRY_ASSERT (builtin_routine_id == ECMA_DATE_PROTOTYPE_SET_DATE || builtin_routine_id == ECMA_DATE_PROTOTYPE_SET_UTC_DATE); day = converted_number[0]; break; } } day_part = ecma_date_make_day (year, month, day); #ifndef CONFIG_DISABLE_ANNEXB_BUILTIN if (builtin_routine_id == ECMA_DATE_PROTOTYPE_SET_YEAR) { builtin_routine_id = ECMA_DATE_PROTOTYPE_SET_UTC_YEAR; if (ecma_number_is_nan (converted_number[0])) { day_part = 0; time_part = converted_number[0]; } } #endif /* !CONFIG_DISABLE_ANNEXB_BUILTIN */ } else { if (ecma_number_is_nan (date_num)) { return ecma_make_number_value (date_num); } day_part = ecma_date_day (date_num); ecma_number_t hour = ecma_date_hour_from_time (date_num); ecma_number_t min = ecma_date_min_from_time (date_num); ecma_number_t sec = ecma_date_sec_from_time (date_num); ecma_number_t ms = ecma_date_ms_from_time (date_num); switch (builtin_routine_id) { case ECMA_DATE_PROTOTYPE_SET_HOURS: case ECMA_DATE_PROTOTYPE_SET_UTC_HOURS: { hour = converted_number[0]; if (conversions >= 2) { min = converted_number[1]; } if (conversions >= 3) { sec = converted_number[2]; } if (conversions >= 4) { ms = converted_number[3]; } break; } case ECMA_DATE_PROTOTYPE_SET_MINUTES: case ECMA_DATE_PROTOTYPE_SET_UTC_MINUTES: { min = converted_number[0]; if (conversions >= 2) { sec = converted_number[1]; } if (conversions >= 3) { ms = converted_number[2]; } break; } case ECMA_DATE_PROTOTYPE_SET_UTC_SECONDS: case ECMA_DATE_PROTOTYPE_SET_SECONDS: { sec = converted_number[0]; if (conversions >= 2) { ms = converted_number[1]; } break; } default: { JERRY_ASSERT (builtin_routine_id == ECMA_DATE_PROTOTYPE_SET_UTC_MILLISECONDS || builtin_routine_id == ECMA_DATE_PROTOTYPE_SET_MILLISECONDS); ms = converted_number[0]; break; } } time_part = ecma_date_make_time (hour, min, sec, ms); } bool is_utc = BUILTIN_DATE_FUNCTION_IS_UTC (builtin_routine_id); ecma_number_t full_date = ecma_date_make_date (day_part, time_part); if (!is_utc) { full_date = ecma_date_utc (full_date); } full_date = ecma_date_time_clip (full_date); *ECMA_GET_INTERNAL_VALUE_POINTER (ecma_number_t, ext_object_p->u.class_prop.u.value) = full_date; return ecma_make_number_value (full_date); } /* ecma_builtin_date_prototype_dispatch_set */
/** * The Date object's 'parse' routine * * See also: * ECMA-262 v5, 15.9.4.2 * ECMA-262 v5, 15.9.1.15 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_date_parse (ecma_value_t this_arg __attr_unused___, /**< this argument */ ecma_value_t arg) /**< string */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); ecma_number_t *date_num_p = ecma_alloc_number (); *date_num_p = ecma_number_make_nan (); /* Date Time String fromat (ECMA-262 v5, 15.9.1.15) */ ECMA_TRY_CATCH (date_str_value, ecma_op_to_string (arg), ret_value); ecma_string_t *date_str_p = ecma_get_string_from_value (date_str_value); lit_utf8_size_t date_str_size = ecma_string_get_size (date_str_p); MEM_DEFINE_LOCAL_ARRAY (date_start_p, date_str_size, lit_utf8_byte_t); ssize_t sz = ecma_string_to_utf8_string (date_str_p, date_start_p, (ssize_t) date_str_size); JERRY_ASSERT (sz >= 0); lit_utf8_byte_t *date_str_curr_p = date_start_p; const lit_utf8_byte_t *date_str_end_p = date_start_p + date_str_size; /* 1. read year */ ecma_number_t year = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 4); if (!ecma_number_is_nan (year) && year >= 0) { ecma_number_t month = ECMA_NUMBER_ONE; ecma_number_t day = ECMA_NUMBER_ONE; ecma_number_t time = ECMA_NUMBER_ZERO; /* 2. read month if any */ if (date_str_curr_p < date_str_end_p && *date_str_curr_p == '-') { /* eat up '-' */ date_str_curr_p++; month = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2); if (month > 12 || month < 1) { month = ecma_number_make_nan (); } } /* 3. read day if any */ if (date_str_curr_p < date_str_end_p && *date_str_curr_p == '-') { /* eat up '-' */ date_str_curr_p++; day = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2); if (day < 1 || day > 31) { day = ecma_number_make_nan (); } } /* 4. read time if any */ if (date_str_curr_p < date_str_end_p && *date_str_curr_p == 'T') { /* eat up 'T' */ date_str_curr_p++; ecma_number_t hours = ECMA_NUMBER_ZERO; ecma_number_t minutes = ECMA_NUMBER_ZERO; ecma_number_t seconds = ECMA_NUMBER_ZERO; ecma_number_t milliseconds = ECMA_NUMBER_ZERO; ecma_length_t remaining_length = lit_utf8_string_length (date_str_curr_p, (lit_utf8_size_t) (date_str_end_p - date_str_curr_p)); if (remaining_length >= 5) { /* 4.1 read hours and minutes */ hours = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2); if (hours < 0 || hours > 24) { hours = ecma_number_make_nan (); } else if (hours == 24) { hours = ECMA_NUMBER_ZERO; } /* eat up ':' */ date_str_curr_p++; minutes = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2); if (minutes < 0 || minutes > 59) { minutes = ecma_number_make_nan (); } /* 4.2 read seconds if any */ if (date_str_curr_p < date_str_end_p && *date_str_curr_p == ':') { /* eat up ':' */ date_str_curr_p++; seconds = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2); if (seconds < 0 || seconds > 59) { seconds = ecma_number_make_nan (); } /* 4.3 read milliseconds if any */ if (date_str_curr_p < date_str_end_p && *date_str_curr_p == '.') { /* eat up '.' */ date_str_curr_p++; milliseconds = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 3); if (milliseconds < 0) { milliseconds = ecma_number_make_nan (); } } } time = ecma_date_make_time (hours, minutes, seconds, milliseconds); } else { time = ecma_number_make_nan (); } /* 4.4 read timezone if any */ if (date_str_curr_p < date_str_end_p && *date_str_curr_p == 'Z' && !ecma_number_is_nan (time)) { date_str_curr_p++; time = ecma_date_make_time (hours, minutes, seconds, milliseconds); } else if (date_str_curr_p < date_str_end_p && (*date_str_curr_p == '+' || *date_str_curr_p == '-')) { ecma_length_t remaining_length; remaining_length = lit_utf8_string_length (date_str_curr_p, (lit_utf8_size_t) (date_str_end_p - date_str_curr_p)) - 1; if (remaining_length == 5) { bool is_negative = false; if (*date_str_curr_p == '-') { is_negative = true; } /* eat up '+/-' */ date_str_curr_p++; /* read hours and minutes */ hours = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2); if (hours < 0 || hours > 24) { hours = ecma_number_make_nan (); } else if (hours == 24) { hours = ECMA_NUMBER_ZERO; } /* eat up ':' */ date_str_curr_p++; minutes = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2); if (minutes < 0 || minutes > 59) { minutes = ecma_number_make_nan (); } if (is_negative) { time += ecma_date_make_time (hours, minutes, ECMA_NUMBER_ZERO, ECMA_NUMBER_ZERO); } else { time -= ecma_date_make_time (hours, minutes, ECMA_NUMBER_ZERO, ECMA_NUMBER_ZERO); } } } } if (date_str_curr_p >= date_str_end_p) { ecma_number_t date = ecma_date_make_day (year, month - 1, day); *date_num_p = ecma_date_make_date (date, time); } } ret_value = ecma_make_normal_completion_value (ecma_make_number_value (date_num_p)); MEM_FINALIZE_LOCAL_ARRAY (date_start_p); ECMA_FINALIZE (date_str_value); return ret_value; } /* ecma_builtin_date_parse */