/** * ToBoolean operation. * * See also: * ECMA-262 v5, 9.2 * * @return completion value * Returned value is simple and so need not be freed. * However, ecma_free_completion_value may be called for it, but it is a no-op. */ ecma_completion_value_t ecma_op_to_boolean (ecma_value_t value) /**< ecma-value */ { ecma_check_value_type_is_spec_defined (value); ecma_simple_value_t ret_value; if (ecma_is_value_boolean (value)) { ret_value = (ecma_is_value_true (value) ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE); } else if (ecma_is_value_undefined (value) || ecma_is_value_null (value)) { ret_value = ECMA_SIMPLE_VALUE_FALSE; } else if (ecma_is_value_number (value)) { ecma_number_t *num_p = ecma_get_number_from_value (value); if (ecma_number_is_nan (*num_p) || ecma_number_is_zero (*num_p)) { ret_value = ECMA_SIMPLE_VALUE_FALSE; } else { ret_value = ECMA_SIMPLE_VALUE_TRUE; } } else if (ecma_is_value_string (value)) { ecma_string_t *str_p = ecma_get_string_from_value (value); if (ecma_string_get_length (str_p) == 0) { ret_value = ECMA_SIMPLE_VALUE_FALSE; } else { ret_value = ECMA_SIMPLE_VALUE_TRUE; } } else { JERRY_ASSERT (ecma_is_value_object (value)); ret_value = ECMA_SIMPLE_VALUE_TRUE; } return ecma_make_simple_completion_value (ret_value); } /* ecma_op_to_boolean */
/** * Helper function to normalizing an array index * * This function clamps the given index to the [0, length] range. * If the index is negative, it is used as the offset from the end of the array, * to compute normalized index. * If the index is greater than the length of the array, the normalized index will be the length of the array. * * See also: * ECMA-262 v5, 15.4.4.10 steps 5-6, 7 (part 2) and 8 * ECMA-262 v5, 15.4.4.12 steps 5-6 * ECMA-262 v5, 15.4.4.14 steps 5 * ECMA-262 v5, 15.5.4.13 steps 4, 5 (part 2) and 6-7 * * Used by: * - The Array.prototype.slice routine. * - The Array.prototype.splice routine. * - The Array.prototype.indexOf routine. * - The String.prototype.slice routine. * * @return uint32_t - the normalized value of the index */ uint32_t ecma_builtin_helper_array_index_normalize (ecma_number_t index, /**< index */ uint32_t length) /**< array's length */ { uint32_t norm_index; if (!ecma_number_is_nan (index)) { if (ecma_number_is_zero (index)) { norm_index = 0; } else if (ecma_number_is_infinity (index)) { norm_index = ecma_number_is_negative (index) ? 0 : length; } else { if (ecma_number_is_negative (index)) { ecma_number_t index_neg = ecma_number_negate (index); if (index_neg > length) { norm_index = 0; } else { norm_index = length - ecma_number_to_uint32 (index_neg); } } else { if (index > length) { norm_index = length; } else { norm_index = ecma_number_to_uint32 (index); } } } } else { norm_index = 0; } return norm_index; } /* ecma_builtin_helper_array_index_normalize */
/** * The Math object's 'round' routine * * See also: * ECMA-262 v5, 15.8.2.15 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_math_object_round (ecma_value_t this_arg __attr_unused___, /**< 'this' argument */ ecma_value_t arg) /**< routine's argument */ { ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); ECMA_OP_TO_NUMBER_TRY_CATCH (arg_num, arg, ret_value); ecma_number_t *num_p = ecma_alloc_number (); if (ecma_number_is_nan (arg_num) || ecma_number_is_zero (arg_num) || ecma_number_is_infinity (arg_num)) { *num_p = arg_num; } else if (ecma_number_is_negative (arg_num) && arg_num >= -0.5f) { *num_p = ecma_number_negate (0.0f); } else { const ecma_number_t up_half = arg_num + 0.5f; const ecma_number_t down_half = arg_num - 0.5f; const ecma_number_t up_rounded = up_half - ecma_op_number_remainder (up_half, 1); const ecma_number_t down_rounded = down_half - ecma_op_number_remainder (down_half, 1); if (up_rounded - arg_num <= arg_num - down_rounded) { *num_p = up_rounded; } else { *num_p = down_rounded; } } ret_value = ecma_make_number_value (num_p); ECMA_OP_TO_NUMBER_FINALIZE (arg_num); return ret_value; } /* ecma_builtin_math_object_round */
/** * ToBoolean operation. Cannot throw an exception. * * See also: * ECMA-262 v5, 9.2 * * @return true if the logical value is true * false otherwise */ bool ecma_op_to_boolean (ecma_value_t value) /**< ecma value */ { ecma_check_value_type_is_spec_defined (value); if (ecma_is_value_simple (value)) { JERRY_ASSERT (ecma_is_value_boolean (value) || ecma_is_value_undefined (value) || ecma_is_value_null (value)); return ecma_is_value_true (value); } if (ecma_is_value_integer_number (value)) { return (value != ecma_make_integer_value (0)); } if (ecma_is_value_float_number (value)) { ecma_number_t num = ecma_get_float_from_value (value); return (!ecma_number_is_nan (num) && !ecma_number_is_zero (num)); } if (ecma_is_value_string (value)) { ecma_string_t *str_p = ecma_get_string_from_value (value); return ecma_string_get_length (str_p) != 0; } JERRY_ASSERT (ecma_is_value_object (value)); return true; } /* ecma_op_to_boolean */
/** * ECMA abstract relational comparison routine. * * See also: ECMA-262 v5, 11.8.5 * * @return ecma value * Returned value must be freed with ecma_free_value */ ecma_value_t ecma_op_abstract_relational_compare (ecma_value_t x, /**< first operand */ ecma_value_t y, /**< second operand */ bool left_first) /**< 'LeftFirst' flag */ { ecma_value_t ret_value = ECMA_VALUE_EMPTY; /* 1., 2. */ ecma_value_t prim_first_converted_value = ecma_op_to_primitive (x, ECMA_PREFERRED_TYPE_NUMBER); if (ECMA_IS_VALUE_ERROR (prim_first_converted_value)) { return prim_first_converted_value; } ecma_value_t prim_second_converted_value = ecma_op_to_primitive (y, ECMA_PREFERRED_TYPE_NUMBER); if (ECMA_IS_VALUE_ERROR (prim_second_converted_value)) { ecma_free_value (prim_first_converted_value); return prim_second_converted_value; } const ecma_value_t px = left_first ? prim_first_converted_value : prim_second_converted_value; const ecma_value_t py = left_first ? prim_second_converted_value : prim_first_converted_value; const bool is_px_string = ecma_is_value_string (px); const bool is_py_string = ecma_is_value_string (py); if (!(is_px_string && is_py_string)) { /* 3. */ /* a. */ ECMA_OP_TO_NUMBER_TRY_CATCH (nx, px, ret_value); ECMA_OP_TO_NUMBER_TRY_CATCH (ny, py, ret_value); /* b. */ if (ecma_number_is_nan (nx) || ecma_number_is_nan (ny)) { /* c., d. */ ret_value = ECMA_VALUE_UNDEFINED; } else { bool is_x_less_than_y = (nx < ny); #ifndef JERRY_NDEBUG bool is_x_less_than_y_check; if (nx == ny || (ecma_number_is_zero (nx) && ecma_number_is_zero (ny))) { /* e., f., g. */ is_x_less_than_y_check = false; } else if (ecma_number_is_infinity (nx) && !ecma_number_is_negative (nx)) { /* h. */ is_x_less_than_y_check = false; } else if (ecma_number_is_infinity (ny) && !ecma_number_is_negative (ny)) { /* i. */ is_x_less_than_y_check = true; } else if (ecma_number_is_infinity (ny) && ecma_number_is_negative (ny)) { /* j. */ is_x_less_than_y_check = false; } else if (ecma_number_is_infinity (nx) && ecma_number_is_negative (nx)) { /* k. */ is_x_less_than_y_check = true; } else { /* l. */ JERRY_ASSERT (!ecma_number_is_nan (nx) && !ecma_number_is_infinity (nx)); JERRY_ASSERT (!ecma_number_is_nan (ny) && !ecma_number_is_infinity (ny)); JERRY_ASSERT (!(ecma_number_is_zero (nx) && ecma_number_is_zero (ny))); if (nx < ny) { is_x_less_than_y_check = true; } else { is_x_less_than_y_check = false; } } JERRY_ASSERT (is_x_less_than_y_check == is_x_less_than_y); #endif /* !JERRY_NDEBUG */ ret_value = ecma_make_boolean_value (is_x_less_than_y); } ECMA_OP_TO_NUMBER_FINALIZE (ny); ECMA_OP_TO_NUMBER_FINALIZE (nx); } else { /* 4. */ JERRY_ASSERT (is_px_string && is_py_string); ecma_string_t *str_x_p = ecma_get_string_from_value (px); ecma_string_t *str_y_p = ecma_get_string_from_value (py); bool is_px_less = ecma_compare_ecma_strings_relational (str_x_p, str_y_p); ret_value = ecma_make_boolean_value (is_px_less); } ecma_free_value (prim_second_converted_value); ecma_free_value (prim_first_converted_value); return ret_value; } /* ecma_op_abstract_relational_compare */
/** * ECMA strict equality comparison routine. * * See also: ECMA-262 v5, 11.9.6 * * @return true - if values are strict equal, * false - otherwise */ bool ecma_op_strict_equality_compare (ecma_value_t x, /**< first operand */ ecma_value_t y) /**< second operand */ { if (ecma_is_value_direct (x) || ecma_is_value_direct (y) #if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) || ecma_is_value_symbol (x) || ecma_is_value_symbol (y) #endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ || ecma_is_value_object (x) || ecma_is_value_object (y)) { JERRY_ASSERT (!ecma_is_value_direct (x) || ecma_is_value_undefined (x) || ecma_is_value_null (x) || ecma_is_value_boolean (x) || ecma_is_value_integer_number (x)); JERRY_ASSERT (!ecma_is_value_direct (y) || ecma_is_value_undefined (y) || ecma_is_value_null (y) || ecma_is_value_boolean (y) || ecma_is_value_integer_number (y)); if ((x != ecma_make_integer_value (0) || !ecma_is_value_float_number (y)) && (y != ecma_make_integer_value (0) || !ecma_is_value_float_number (x))) { return (x == y); } /* The +0 === -0 case handled below. */ } JERRY_ASSERT (ecma_is_value_number (x) || ecma_is_value_string (x)); JERRY_ASSERT (ecma_is_value_number (y) || ecma_is_value_string (y)); if (ecma_is_value_string (x)) { if (!ecma_is_value_string (y)) { return false; } ecma_string_t *x_str_p = ecma_get_string_from_value (x); ecma_string_t *y_str_p = ecma_get_string_from_value (y); return ecma_compare_ecma_strings (x_str_p, y_str_p); } if (!ecma_is_value_number (y)) { return false; } ecma_number_t x_num = ecma_get_number_from_value (x); ecma_number_t y_num = ecma_get_number_from_value (y); bool is_x_equal_to_y = (x_num == y_num); #ifndef JERRY_NDEBUG bool is_x_equal_to_y_check; if (ecma_number_is_nan (x_num) || ecma_number_is_nan (y_num)) { is_x_equal_to_y_check = false; } else if (x_num == y_num || (ecma_number_is_zero (x_num) && ecma_number_is_zero (y_num))) { is_x_equal_to_y_check = true; } else { is_x_equal_to_y_check = false; } JERRY_ASSERT (is_x_equal_to_y == is_x_equal_to_y_check); #endif /* !JERRY_NDEBUG */ return is_x_equal_to_y; } /* ecma_op_strict_equality_compare */
/** * The Number.prototype object's 'toPrecision' routine * * See also: * ECMA-262 v5, 15.7.4.7 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_number_prototype_object_to_precision (ecma_value_t this_arg, /**< this argument */ ecma_value_t arg) /**< routine's argument */ { ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); /* 1. */ ECMA_TRY_CATCH (this_value, ecma_builtin_number_prototype_object_value_of (this_arg), ret_value); ecma_number_t this_num = ecma_get_number_from_value (this_value); /* 2. */ if (ecma_is_value_undefined (arg)) { ret_value = ecma_builtin_number_prototype_object_to_string (this_arg, NULL, 0); } else { /* 3. */ ECMA_OP_TO_NUMBER_TRY_CATCH (arg_num, arg, ret_value); /* 4. */ if (ecma_number_is_nan (this_num)) { ecma_string_t *nan_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_NAN); ret_value = ecma_make_string_value (nan_str_p); } else { /* 6. */ bool is_negative = false; if (ecma_number_is_negative (this_num) && !ecma_number_is_zero (this_num)) { is_negative = true; this_num *= -1; } /* 7. */ if (ecma_number_is_infinity (this_num)) { ecma_string_t *infinity_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_INFINITY_UL); if (is_negative) { ecma_string_t *neg_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_MINUS_CHAR); ecma_string_t *neg_inf_str_p = ecma_concat_ecma_strings (neg_str_p, infinity_str_p); ecma_deref_ecma_string (infinity_str_p); ecma_deref_ecma_string (neg_str_p); ret_value = ecma_make_string_value (neg_inf_str_p); } else { ret_value = ecma_make_string_value (infinity_str_p); } } /* 8. */ else if (arg_num < 1.0 || arg_num >= 22.0) { ret_value = ecma_raise_range_error (ECMA_ERR_MSG ("")); } else { /* Get the parameters of the number if non-zero. */ lit_utf8_byte_t digits[ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER]; lit_utf8_size_t num_digits; int32_t exponent; if (!ecma_number_is_zero (this_num)) { num_digits = ecma_number_to_decimal (this_num, digits, &exponent); } else { digits[0] = '0'; num_digits = 1; exponent = 1; } int32_t precision = ecma_number_to_int32 (arg_num); num_digits = ecma_builtin_number_prototype_helper_round (digits, num_digits, precision); int buffer_size; if (exponent < -5 || exponent > precision) { /* Exponential notation, precision + 1 digits for number, 5 for exponent, 1 for \0 */ buffer_size = precision + 1 + 5 + 1; } else if (exponent <= 0) { /* Fixed notation, -exponent + 2 digits for leading zeros, precision digits, 1 for \0 */ buffer_size = -exponent + 2 + precision + 1; } else { /* Fixed notation, precision + 1 digits for number, 1 for \0 */ buffer_size = precision + 1 + 1; } if (is_negative) { buffer_size++; } JMEM_DEFINE_LOCAL_ARRAY (buff, buffer_size, lit_utf8_byte_t); lit_utf8_byte_t *actual_char_p = buff; if (is_negative) { *actual_char_p++ = '-'; } /* 10.c, Exponential notation.*/ if (exponent < -5 || exponent > precision) { actual_char_p += ecma_builtin_number_prototype_helper_to_string (digits, num_digits, 1, actual_char_p, (lit_utf8_size_t) precision); *actual_char_p++ = 'e'; exponent--; if (exponent < 0) { exponent *= -1; *actual_char_p++ = '-'; } else { *actual_char_p++ = '+'; } /* Add exponent digits. */ actual_char_p += ecma_uint32_to_utf8_string ((uint32_t) exponent, actual_char_p, 3); } /* Fixed notation. */ else { lit_utf8_size_t to_num_digits = ((exponent <= 0) ? (lit_utf8_size_t) (1 - exponent + precision) : (lit_utf8_size_t) precision); actual_char_p += ecma_builtin_number_prototype_helper_to_string (digits, num_digits, exponent, actual_char_p, to_num_digits); } JERRY_ASSERT (actual_char_p - buff < buffer_size); *actual_char_p = '\0'; ecma_string_t *str_p = ecma_new_ecma_string_from_utf8 (buff, (lit_utf8_size_t) (actual_char_p - buff)); ret_value = ecma_make_string_value (str_p); JMEM_FINALIZE_LOCAL_ARRAY (buff); } } ECMA_OP_TO_NUMBER_FINALIZE (arg_num); } ECMA_FINALIZE (this_value); return ret_value; } /* ecma_builtin_number_prototype_object_to_precision */
/** * The Number.prototype object's 'toExponential' routine * * See also: * ECMA-262 v5, 15.7.4.6 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_number_prototype_object_to_exponential (ecma_value_t this_arg, /**< this argument */ ecma_value_t arg) /**< routine's argument */ { ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); /* 1. */ ECMA_TRY_CATCH (this_value, ecma_builtin_number_prototype_object_value_of (this_arg), ret_value); ecma_number_t this_num = ecma_get_number_from_value (this_value); ECMA_OP_TO_NUMBER_TRY_CATCH (arg_num, arg, ret_value); /* 7. */ if (arg_num <= -1.0 || arg_num >= 21.0) { ret_value = ecma_raise_range_error (ECMA_ERR_MSG ("")); } else { /* 3. */ if (ecma_number_is_nan (this_num)) { ecma_string_t *nan_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_NAN); ret_value = ecma_make_string_value (nan_str_p); } else { /* 5. */ bool is_negative = false; if (ecma_number_is_negative (this_num) && !ecma_number_is_zero (this_num)) { is_negative = true; this_num *= -1; } /* 6. */ if (ecma_number_is_infinity (this_num)) { ecma_string_t *infinity_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_INFINITY_UL); if (is_negative) { ecma_string_t *neg_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_MINUS_CHAR); ecma_string_t *neg_inf_str_p = ecma_concat_ecma_strings (neg_str_p, infinity_str_p); ecma_deref_ecma_string (infinity_str_p); ecma_deref_ecma_string (neg_str_p); ret_value = ecma_make_string_value (neg_inf_str_p); } else { ret_value = ecma_make_string_value (infinity_str_p); } } else { /* Get the parameters of the number if non zero. */ lit_utf8_byte_t digits[ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER]; lit_utf8_size_t num_digits; int32_t exponent; if (!ecma_number_is_zero (this_num)) { num_digits = ecma_number_to_decimal (this_num, digits, &exponent); } else { digits[0] = '0'; num_digits = 1; exponent = 1; } int32_t frac_digits; if (ecma_is_value_undefined (arg)) { frac_digits = (int32_t) num_digits - 1; } else { frac_digits = ecma_number_to_int32 (arg_num); } num_digits = ecma_builtin_number_prototype_helper_round (digits, num_digits, frac_digits + 1); /* frac_digits + 2 characters for number, 5 characters for exponent, 1 for \0. */ int buffer_size = frac_digits + 2 + 5 + 1; if (is_negative) { /* +1 character for sign. */ buffer_size++; } JMEM_DEFINE_LOCAL_ARRAY (buff, buffer_size, lit_utf8_byte_t); lit_utf8_byte_t *actual_char_p = buff; if (is_negative) { *actual_char_p++ = '-'; } actual_char_p += ecma_builtin_number_prototype_helper_to_string (digits, num_digits, 1, actual_char_p, (lit_utf8_size_t) (frac_digits + 1)); *actual_char_p++ = 'e'; exponent--; if (exponent < 0) { exponent *= -1; *actual_char_p++ = '-'; } else { *actual_char_p++ = '+'; } /* Add exponent digits. */ actual_char_p += ecma_uint32_to_utf8_string ((uint32_t) exponent, actual_char_p, 3); JERRY_ASSERT (actual_char_p - buff < buffer_size); *actual_char_p = '\0'; ecma_string_t *str = ecma_new_ecma_string_from_utf8 (buff, (lit_utf8_size_t) (actual_char_p - buff)); ret_value = ecma_make_string_value (str); JMEM_FINALIZE_LOCAL_ARRAY (buff); } } } ECMA_OP_TO_NUMBER_FINALIZE (arg_num); ECMA_FINALIZE (this_value); return ret_value; } /* ecma_builtin_number_prototype_object_to_exponential */
/** * The Number.prototype object's 'toFixed' routine * * See also: * ECMA-262 v5, 15.7.4.5 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_number_prototype_object_to_fixed (ecma_value_t this_arg, /**< this argument */ ecma_value_t arg) /**< routine's argument */ { ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); ECMA_TRY_CATCH (this_value, ecma_builtin_number_prototype_object_value_of (this_arg), ret_value); ecma_number_t this_num = ecma_get_number_from_value (this_value); ECMA_OP_TO_NUMBER_TRY_CATCH (arg_num, arg, ret_value); /* 2. */ if (arg_num <= -1 || arg_num >= 21) { ret_value = ecma_raise_range_error (ECMA_ERR_MSG ("")); } else { /* 4. */ if (ecma_number_is_nan (this_num)) { ecma_string_t *nan_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_NAN); ret_value = ecma_make_string_value (nan_str_p); } else { /* 6. */ bool is_negative = false; if (ecma_number_is_negative (this_num)) { is_negative = true; this_num *= -1; } /* We handle infinities separately. */ if (ecma_number_is_infinity (this_num)) { ecma_string_t *infinity_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_INFINITY_UL); if (is_negative) { ecma_string_t *neg_str_p = ecma_new_ecma_string_from_utf8 ((const lit_utf8_byte_t *) "-", 1); ecma_string_t *neg_inf_str_p = ecma_concat_ecma_strings (neg_str_p, infinity_str_p); ecma_deref_ecma_string (infinity_str_p); ecma_deref_ecma_string (neg_str_p); ret_value = ecma_make_string_value (neg_inf_str_p); } else { ret_value = ecma_make_string_value (infinity_str_p); } } else { /* Get the parameters of the number if non-zero. */ lit_utf8_byte_t digits[ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER]; lit_utf8_size_t num_digits; int32_t exponent; if (!ecma_number_is_zero (this_num)) { num_digits = ecma_number_to_decimal (this_num, digits, &exponent); } else { digits[0] = '0'; num_digits = 1; exponent = 1; } /* 7. */ if (exponent > 21) { ret_value = ecma_builtin_number_prototype_object_to_string (this_arg, NULL, 0); } /* 8. */ else { /* 1. */ int32_t frac_digits = ecma_number_to_int32 (arg_num); num_digits = ecma_builtin_number_prototype_helper_round (digits, num_digits, exponent + frac_digits); /* Buffer that is used to construct the string. */ int buffer_size = (exponent > 0) ? exponent + frac_digits + 2 : frac_digits + 3; if (is_negative) { buffer_size++; } JERRY_ASSERT (buffer_size > 0); JMEM_DEFINE_LOCAL_ARRAY (buff, buffer_size, lit_utf8_byte_t); lit_utf8_byte_t *p = buff; if (is_negative) { *p++ = '-'; } lit_utf8_size_t to_num_digits = ((exponent > 0) ? (lit_utf8_size_t) (exponent + frac_digits) : (lit_utf8_size_t) (frac_digits + 1)); p += ecma_builtin_number_prototype_helper_to_string (digits, num_digits, exponent, p, to_num_digits); JERRY_ASSERT (p - buff < buffer_size); /* String terminator. */ *p = 0; ecma_string_t *str = ecma_new_ecma_string_from_utf8 (buff, (lit_utf8_size_t) (p - buff)); ret_value = ecma_make_string_value (str); JMEM_FINALIZE_LOCAL_ARRAY (buff); } } } } ECMA_OP_TO_NUMBER_FINALIZE (arg_num); ECMA_FINALIZE (this_value); return ret_value; } /* ecma_builtin_number_prototype_object_to_fixed */
/** * The Number.prototype object's 'toString' routine * * See also: * ECMA-262 v5, 15.7.4.2 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_number_prototype_object_to_string (ecma_value_t this_arg, /**< this argument */ const ecma_value_t *arguments_list_p, /**< arguments list */ ecma_length_t arguments_list_len) /**< number of arguments */ { ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); ECMA_TRY_CATCH (this_value, ecma_builtin_number_prototype_object_value_of (this_arg), ret_value); ecma_number_t this_arg_number = ecma_get_number_from_value (this_value); if (arguments_list_len == 0 || ecma_number_is_nan (this_arg_number) || ecma_number_is_infinity (this_arg_number) || ecma_number_is_zero (this_arg_number) || (arguments_list_len > 0 && ecma_is_value_undefined (arguments_list_p[0]))) { ecma_string_t *ret_str_p = ecma_new_ecma_string_from_number (this_arg_number); ret_value = ecma_make_string_value (ret_str_p); } else { static const lit_utf8_byte_t digit_chars[36] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; ECMA_OP_TO_NUMBER_TRY_CATCH (arg_num, arguments_list_p[0], ret_value); uint32_t radix = ecma_number_to_uint32 (arg_num); if (radix < 2 || radix > 36) { ret_value = ecma_raise_range_error (ECMA_ERR_MSG ("")); } else if (radix == 10) { ecma_string_t *ret_str_p = ecma_new_ecma_string_from_number (this_arg_number); ret_value = ecma_make_string_value (ret_str_p); } else { bool is_negative = false; if (ecma_number_is_negative (this_arg_number)) { this_arg_number = -this_arg_number; is_negative = true; } lit_utf8_byte_t digits[ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER]; int32_t exponent; lit_utf8_size_t num_digits = ecma_number_to_decimal (this_arg_number, digits, &exponent); exponent = exponent - (int32_t) num_digits; /* Calculate the scale of the number in the specified radix. */ int scale = (int) -floor ((log (10) / log (radix)) * exponent); bool is_scale_negative = false; if (scale < 0) { is_scale_negative = true; scale = -scale; } int buff_size; if (is_scale_negative) { buff_size = (int) floor (log (this_arg_number) / log (radix)) + 1; } else { buff_size = scale + ECMA_NUMBER_FRACTION_WIDTH + 2; } if (is_negative) { buff_size++; } /* Normalize the number, so that it is as close to 0 exponent as possible. */ if (is_scale_negative) { for (int i = 0; i < scale; i++) { this_arg_number /= (ecma_number_t) radix; } } else { for (int i = 0; i < scale; i++) { this_arg_number *= (ecma_number_t) radix; } } uint64_t whole = (uint64_t) this_arg_number; ecma_number_t fraction = this_arg_number - (ecma_number_t) whole; bool should_round = false; if (!ecma_number_is_zero (fraction) && is_scale_negative) { /* Add one extra digit for rounding. */ buff_size++; should_round = true; } JMEM_DEFINE_LOCAL_ARRAY (buff, buff_size, lit_utf8_byte_t); int buff_index = 0; /* Calculate digits for whole part. */ while (whole > 0) { buff[buff_index++] = (lit_utf8_byte_t) (whole % radix); whole /= radix; } /* Calculate where we have to put the radix point. */ int point = is_scale_negative ? buff_index + scale : buff_index - scale; /* Reverse the digits, since they are backwards. */ for (int i = 0; i < buff_index / 2; i++) { lit_utf8_byte_t swap = buff[i]; buff[i] = buff[buff_index - i - 1]; buff[buff_index - i - 1] = swap; } int required_digits = buff_size; if (is_negative) { required_digits--; } if (!is_scale_negative) { /* Leave space for leading zeros / radix point. */ required_digits -= scale + 1; } /* Calculate digits for fractional part. */ while (buff_index < required_digits && (fraction != 0 || is_scale_negative)) { fraction *= (ecma_number_t) radix; lit_utf8_byte_t digit = (lit_utf8_byte_t) floor (fraction); buff[buff_index++] = digit; fraction -= (ecma_number_t) floor (fraction); } if (should_round) { /* Round off last digit. */ if (buff[buff_index - 1] > radix / 2) { buff[buff_index - 2]++; } buff_index--; /* Propagate carry. */ for (int i = buff_index - 1; i > 0 && buff[i] >= radix; i--) { buff[i] = (lit_utf8_byte_t) (buff[i] - radix); buff[i - 1]++; } /* Carry propagated over the whole number, need to add a leading digit. */ if (buff[0] >= radix) { memmove (buff + 1, buff, (size_t) buff_index); buff_index++; buff[0] = 1; } } /* Remove trailing zeros from fraction. */ while (buff_index - 1 > point && buff[buff_index - 1] == 0) { buff_index--; } /* Add leading zeros in case place of radix point is negative. */ if (point <= 0) { memmove (buff - point + 1, buff, (size_t) buff_index); buff_index += -point + 1; for (int i = 0; i < -point + 1; i++) { buff[i] = 0; } point = 1; } /* Convert digits to characters. */ for (int i = 0; i < buff_index; i++) { buff[i] = digit_chars[buff[i]]; } /* Place radix point to the required position. */ if (point < buff_index) { memmove (buff + point + 1, buff + point, (size_t) buff_index); buff[point] = '.'; buff_index++; } /* Add negative sign if necessary. */ if (is_negative) { memmove (buff + 1, buff, (size_t) buff_index); buff_index++; buff[0] = '-'; } JERRY_ASSERT (buff_index <= buff_size); ecma_string_t *str_p = ecma_new_ecma_string_from_utf8 (buff, (lit_utf8_size_t) buff_index); ret_value = ecma_make_string_value (str_p); JMEM_FINALIZE_LOCAL_ARRAY (buff); } ECMA_OP_TO_NUMBER_FINALIZE (arg_num); } ECMA_FINALIZE (this_value); return ret_value; } /* ecma_builtin_number_prototype_object_to_string */
/** * The Number.prototype object's 'toExponential' routine * * See also: * ECMA-262 v5, 15.7.4.6 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_number_prototype_object_to_exponential (ecma_value_t this_arg, /**< this argument */ ecma_value_t arg) /**< routine's argument */ { ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); /* 1. */ ECMA_TRY_CATCH (this_value, ecma_builtin_number_prototype_object_value_of (this_arg), ret_value); ecma_number_t this_num = *ecma_get_number_from_value (this_value); ECMA_OP_TO_NUMBER_TRY_CATCH (arg_num, arg, ret_value); /* 7. */ if (arg_num <= -1.0 || arg_num >= 21.0) { ret_value = ecma_raise_range_error (ECMA_ERR_MSG ("")); } else { /* 3. */ if (ecma_number_is_nan (this_num)) { ecma_string_t *nan_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_NAN); ret_value = ecma_make_string_value (nan_str_p); } else { bool is_negative = false; /* 5. */ if (ecma_number_is_negative (this_num) && !ecma_number_is_zero (this_num)) { is_negative = true; this_num *= -1; } /* 6. */ if (ecma_number_is_infinity (this_num)) { ecma_string_t *infinity_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_INFINITY_UL); if (is_negative) { ecma_string_t *neg_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_MINUS_CHAR); ecma_string_t *neg_inf_str_p = ecma_concat_ecma_strings (neg_str_p, infinity_str_p); ecma_deref_ecma_string (infinity_str_p); ecma_deref_ecma_string (neg_str_p); ret_value = ecma_make_string_value (neg_inf_str_p); } else { ret_value = ecma_make_string_value (infinity_str_p); } } else { uint64_t digits = 0; int32_t num_digits = 0; int32_t exponent = 1; if (!ecma_number_is_zero (this_num)) { /* Get the parameters of the number if non zero. */ ecma_number_to_decimal (this_num, &digits, &num_digits, &exponent); } int32_t frac_digits; if (ecma_is_value_undefined (arg)) { frac_digits = num_digits - 1; } else { frac_digits = ecma_number_to_int32 (arg_num); } digits = ecma_builtin_number_prototype_helper_round (digits, num_digits - frac_digits - 1); /* frac_digits + 2 characters for number, 5 characters for exponent, 1 for \0. */ int buffer_size = frac_digits + 2 + 5 + 1; if (is_negative) { /* +1 character for sign. */ buffer_size++; } MEM_DEFINE_LOCAL_ARRAY (buff, buffer_size, lit_utf8_byte_t); int digit = 0; uint64_t scale = 1; /* Calculate the magnitude of the number. This is used to get the digits from left to right. */ while (scale <= digits) { scale *= 10; } lit_utf8_byte_t *actual_char_p = buff; if (is_negative) { *actual_char_p++ = '-'; } /* Add significant digits. */ for (int i = 0; i <= frac_digits; i++) { digit = 0; scale /= 10; while (digits >= scale && scale > 0) { digits -= scale; digit++; } *actual_char_p = (lit_utf8_byte_t) (digit + '0'); actual_char_p++; if (i == 0 && frac_digits != 0) { *actual_char_p++ = '.'; } } *actual_char_p++ = 'e'; exponent--; if (exponent < 0) { exponent *= -1; *actual_char_p++ = '-'; } else { *actual_char_p++ = '+'; } /* Get magnitude of exponent. */ int32_t scale_expt = 1; while (scale_expt <= exponent) { scale_expt *= 10; } scale_expt /= 10; /* Add exponent digits. */ if (exponent == 0) { *actual_char_p++ = '0'; } else { while (scale_expt > 0) { digit = exponent / scale_expt; exponent %= scale_expt; *actual_char_p++ = (lit_utf8_byte_t) (digit + '0'); scale_expt /= 10; } } JERRY_ASSERT (actual_char_p - buff < buffer_size); *actual_char_p = '\0'; ecma_string_t *str = ecma_new_ecma_string_from_utf8 (buff, (lit_utf8_size_t) (actual_char_p - buff)); ret_value = ecma_make_string_value (str); MEM_FINALIZE_LOCAL_ARRAY (buff); } } } ECMA_OP_TO_NUMBER_FINALIZE (arg_num); ECMA_FINALIZE (this_value); return ret_value; } /* ecma_builtin_number_prototype_object_to_exponential */
/** * SameValue operation. * * See also: * ECMA-262 v5, 9.12 * * @return true - if the value are same according to ECMA-defined SameValue algorithm, * false - otherwise. */ bool ecma_op_same_value (ecma_value_t x, /**< ecma-value */ ecma_value_t y) /**< ecma-value */ { const bool is_x_undefined = ecma_is_value_undefined (x); const bool is_x_null = ecma_is_value_null (x); const bool is_x_boolean = ecma_is_value_boolean (x); const bool is_x_number = ecma_is_value_number (x); const bool is_x_string = ecma_is_value_string (x); const bool is_x_object = ecma_is_value_object (x); const bool is_y_undefined = ecma_is_value_undefined (y); const bool is_y_null = ecma_is_value_null (y); const bool is_y_boolean = ecma_is_value_boolean (y); const bool is_y_number = ecma_is_value_number (y); const bool is_y_string = ecma_is_value_string (y); const bool is_y_object = ecma_is_value_object (y); const bool is_types_equal = ((is_x_undefined && is_y_undefined) || (is_x_null && is_y_null) || (is_x_boolean && is_y_boolean) || (is_x_number && is_y_number) || (is_x_string && is_y_string) || (is_x_object && is_y_object)); if (!is_types_equal) { return false; } if (is_x_undefined || is_x_null) { return true; } if (is_x_number) { ecma_number_t *x_num_p = ecma_get_number_from_value (x); ecma_number_t *y_num_p = ecma_get_number_from_value (y); if (ecma_number_is_nan (*x_num_p) && ecma_number_is_nan (*y_num_p)) { return true; } else if (ecma_number_is_zero (*x_num_p) && ecma_number_is_zero (*y_num_p) && ecma_number_is_negative (*x_num_p) != ecma_number_is_negative (*y_num_p)) { return false; } return (*x_num_p == *y_num_p); } if (is_x_string) { ecma_string_t* x_str_p = ecma_get_string_from_value (x); ecma_string_t* y_str_p = ecma_get_string_from_value (y); return ecma_compare_ecma_strings (x_str_p, y_str_p); } if (is_x_boolean) { return (ecma_is_value_true (x) == ecma_is_value_true (y)); } JERRY_ASSERT (is_x_object); return (ecma_get_object_from_value (x) == ecma_get_object_from_value (y)); } /* ecma_op_same_value */
/** * The Math object's 'min' routine * * See also: * ECMA-262 v5, 15.8.2.12 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_math_object_min (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_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); ecma_number_t ret_num = ecma_number_make_infinity (false); bool is_NaN = false; for (ecma_length_t arg_index = 0; arg_index < args_number && ecma_is_value_empty (ret_value); arg_index++) { ECMA_OP_TO_NUMBER_TRY_CATCH (arg_num, args[arg_index], ret_value); if (!is_NaN) { if (unlikely (ecma_number_is_nan (arg_num))) { ret_num = arg_num; is_NaN = true; } else if (ecma_number_is_zero (arg_num) /* both numbers are zeroes */ && ecma_number_is_zero (ret_num)) { if (ecma_number_is_negative (arg_num)) { ret_num = arg_num; } } else if (ecma_number_is_infinity (arg_num)) { if (ecma_number_is_negative (arg_num)) { ret_num = arg_num; } } else if (ecma_number_is_infinity (ret_num)) { if (!ecma_number_is_negative (ret_num)) { ret_num = arg_num; } } else { JERRY_ASSERT (!ecma_number_is_nan (arg_num) && !ecma_number_is_infinity (arg_num)); JERRY_ASSERT (!ecma_number_is_nan (ret_num) && !ecma_number_is_infinity (ret_num)); if (arg_num < ret_num) { ret_num = arg_num; } } } ECMA_OP_TO_NUMBER_FINALIZE (arg_num); } if (ecma_is_value_empty (ret_value)) { ecma_number_t *num_p = ecma_alloc_number (); *num_p = ret_num; ret_value = ecma_make_number_value (num_p); } return ret_value; } /* ecma_builtin_math_object_min */
/** * The Number.prototype object's 'toPrecision' routine * * See also: * ECMA-262 v5, 15.7.4.7 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_number_prototype_object_to_precision (ecma_value_t this_arg, /**< this argument */ ecma_value_t arg) /**< routine's argument */ { ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); /* 1. */ ECMA_TRY_CATCH (this_value, ecma_builtin_number_prototype_object_value_of (this_arg), ret_value); ecma_number_t this_num = *ecma_get_number_from_value (this_value); /* 2. */ if (ecma_is_value_undefined (arg)) { ret_value = ecma_builtin_number_prototype_object_to_string (this_arg, NULL, 0); } else { /* 3. */ ECMA_OP_TO_NUMBER_TRY_CATCH (arg_num, arg, ret_value); /* 4. */ if (ecma_number_is_nan (this_num)) { ecma_string_t *nan_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_NAN); ret_value = ecma_make_string_value (nan_str_p); } else { bool is_negative = false; /* 6. */ if (ecma_number_is_negative (this_num) && !ecma_number_is_zero (this_num)) { is_negative = true; this_num *= -1; } /* 7. */ if (ecma_number_is_infinity (this_num)) { ecma_string_t *infinity_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_INFINITY_UL); if (is_negative) { ecma_string_t *neg_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_MINUS_CHAR); ecma_string_t *neg_inf_str_p = ecma_concat_ecma_strings (neg_str_p, infinity_str_p); ecma_deref_ecma_string (infinity_str_p); ecma_deref_ecma_string (neg_str_p); ret_value = ecma_make_string_value (neg_inf_str_p); } else { ret_value = ecma_make_string_value (infinity_str_p); } } /* 8. */ else if (arg_num < 1.0 || arg_num >= 22.0) { ret_value = ecma_raise_range_error (ECMA_ERR_MSG ("")); } else { uint64_t digits = 0; int32_t num_digits = 0; int32_t exponent = 1; int32_t precision = ecma_number_to_int32 (arg_num); /* Get the parameters of the number if non-zero. */ if (!ecma_number_is_zero (this_num)) { ecma_number_to_decimal (this_num, &digits, &num_digits, &exponent); } digits = ecma_builtin_number_prototype_helper_round (digits, num_digits - precision); int buffer_size; if (exponent < -5 || exponent > precision) { /* Exponential notation, precision + 1 digits for number, 5 for exponent, 1 for \0 */ buffer_size = precision + 1 + 5 + 1; } else if (exponent <= 0) { /* Fixed notation, -exponent + 2 digits for leading zeros, precision digits, 1 for \0 */ buffer_size = -exponent + 2 + precision + 1; } else { /* Fixed notation, precision + 1 digits for number, 1 for \0 */ buffer_size = precision + 1 + 1; } if (is_negative) { buffer_size++; } MEM_DEFINE_LOCAL_ARRAY (buff, buffer_size, lit_utf8_byte_t); lit_utf8_byte_t *actual_char_p = buff; uint64_t scale = 1; /* Calculate the magnitude of the number. This is used to get the digits from left to right. */ while (scale <= digits) { scale *= 10; } if (is_negative) { *actual_char_p++ = '-'; } int digit = 0; /* 10.c, Exponential notation.*/ if (exponent < -5 || exponent > precision) { /* Add significant digits. */ for (int i = 1; i <= precision; i++) { digit = 0; scale /= 10; while (digits >= scale && scale > 0) { digits -= scale; digit++; } *actual_char_p++ = (lit_utf8_byte_t) (digit + '0'); if (i == 1 && i != precision) { *actual_char_p++ = '.'; } } *actual_char_p++ = 'e'; exponent--; if (exponent < 0) { exponent *= -1; *actual_char_p++ = '-'; } else { *actual_char_p++ = '+'; } /* Get magnitude of exponent. */ int32_t scale_expt = 1; while (scale_expt <= exponent) { scale_expt *= 10; } scale_expt /= 10; /* Add exponent digits. */ if (exponent == 0) { *actual_char_p++ = '0'; } else { while (scale_expt > 0) { digit = exponent / scale_expt; exponent %= scale_expt; *actual_char_p++ = (lit_utf8_byte_t) (digit + '0'); scale_expt /= 10; } } } /* Fixed notation. */ else { /* Add leading zeros if neccessary. */ if (exponent <= 0) { *actual_char_p++ = '0'; *actual_char_p++ = '.'; for (int i = exponent; i < 0; i++) { *actual_char_p++ = '0'; } } /* Add significant digits. */ for (int i = 1; i <= precision; i++) { digit = 0; scale /= 10; while (digits >= scale && scale > 0) { digits -= scale; digit++; } *actual_char_p++ = (lit_utf8_byte_t) (digit + '0'); if (i == exponent && i != precision) { *actual_char_p++ = '.'; } } } JERRY_ASSERT (actual_char_p - buff < buffer_size); *actual_char_p = '\0'; ecma_string_t *str_p = ecma_new_ecma_string_from_utf8 (buff, (lit_utf8_size_t) (actual_char_p - buff)); ret_value = ecma_make_string_value (str_p); MEM_FINALIZE_LOCAL_ARRAY (buff); } } ECMA_OP_TO_NUMBER_FINALIZE (arg_num); } ECMA_FINALIZE (this_value); return ret_value; } /* ecma_builtin_number_prototype_object_to_precision */
/** * ECMA abstract equality comparison routine. * * See also: ECMA-262 v5, 11.9.3 * * Note: * This function might raise an exception, so the * returned value must be freed with ecma_free_value. * * @return true - if values are equal, * false - otherwise * error - in case of any problems */ ecma_value_t ecma_op_abstract_equality_compare (ecma_value_t x, /**< first operand */ ecma_value_t y) /**< second operand */ { if (x == y) { return ECMA_VALUE_TRUE; } if (ecma_are_values_integer_numbers (x, y)) { /* Note: the (x == y) comparison captures the true case. */ return ECMA_VALUE_FALSE; } if (ecma_is_value_number (x)) { if (ecma_is_value_number (y)) { /* 1.c */ ecma_number_t x_num = ecma_get_number_from_value (x); ecma_number_t y_num = ecma_get_number_from_value (y); bool is_x_equal_to_y = (x_num == y_num); #ifndef JERRY_NDEBUG bool is_x_equal_to_y_check; if (ecma_number_is_nan (x_num) || ecma_number_is_nan (y_num)) { is_x_equal_to_y_check = false; } else if (x_num == y_num || (ecma_number_is_zero (x_num) && ecma_number_is_zero (y_num))) { is_x_equal_to_y_check = true; } else { is_x_equal_to_y_check = false; } JERRY_ASSERT (is_x_equal_to_y == is_x_equal_to_y_check); #endif /* !JERRY_NDEBUG */ return ecma_make_boolean_value (is_x_equal_to_y); } /* Swap values. */ ecma_value_t tmp = x; x = y; y = tmp; } if (ecma_is_value_string (x)) { if (ecma_is_value_string (y)) { /* 1., d. */ ecma_string_t *x_str_p = ecma_get_string_from_value (x); ecma_string_t *y_str_p = ecma_get_string_from_value (y); bool is_equal = ecma_compare_ecma_strings (x_str_p, y_str_p); return ecma_make_boolean_value (is_equal); } if (ecma_is_value_number (y)) { /* 4. */ ecma_value_t x_num_value = ecma_op_to_number (x); if (ECMA_IS_VALUE_ERROR (x_num_value)) { return x_num_value; } ecma_value_t compare_result = ecma_op_abstract_equality_compare (x_num_value, y); ecma_free_value (x_num_value); return compare_result; } /* Swap values. */ ecma_value_t tmp = x; x = y; y = tmp; } #if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) if (ecma_is_value_symbol (x)) { return ECMA_VALUE_FALSE; } #endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ if (ecma_is_value_boolean (y)) { if (ecma_is_value_boolean (x)) { /* 1., e. */ /* Note: the (x == y) comparison captures the true case. */ return ECMA_VALUE_FALSE; } /* 7. */ return ecma_op_abstract_equality_compare (x, ecma_make_integer_value (ecma_is_value_true (y) ? 1 : 0)); } if (ecma_is_value_object (x)) { if (ecma_is_value_string (y) #if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) || ecma_is_value_symbol (y) #endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ || ecma_is_value_number (y)) { /* 9. */ ecma_value_t x_prim_value = ecma_op_to_primitive (x, ECMA_PREFERRED_TYPE_NO); if (ECMA_IS_VALUE_ERROR (x_prim_value)) { return x_prim_value; } ecma_value_t compare_result = ecma_op_abstract_equality_compare (x_prim_value, y); ecma_free_value (x_prim_value); return compare_result; } /* 1., f. */ /* Note: the (x == y) comparison captures the true case. */ return ECMA_VALUE_FALSE; } if (ecma_is_value_boolean (x)) { /* 6. */ return ecma_op_abstract_equality_compare (ecma_make_integer_value (ecma_is_value_true (x) ? 1 : 0), y); } if (ecma_is_value_undefined (x) || ecma_is_value_null (x)) { /* 1. a., b. */ /* 2., 3. */ bool is_equal = ecma_is_value_undefined (y) || ecma_is_value_null (y); return ecma_make_boolean_value (is_equal); } return ECMA_VALUE_FALSE; } /* ecma_op_abstract_equality_compare */
/** * SameValue operation. * * See also: * ECMA-262 v5, 9.12 * * @return true - if the value are same according to ECMA-defined SameValue algorithm, * false - otherwise. */ bool ecma_op_same_value (ecma_value_t x, /**< ecma value */ ecma_value_t y) /**< ecma value */ { const bool is_x_undefined = ecma_is_value_undefined (x); const bool is_x_null = ecma_is_value_null (x); const bool is_x_boolean = ecma_is_value_boolean (x); const bool is_x_number = ecma_is_value_number (x); const bool is_x_string = ecma_is_value_string (x); const bool is_x_object = ecma_is_value_object (x); const bool is_y_undefined = ecma_is_value_undefined (y); const bool is_y_null = ecma_is_value_null (y); const bool is_y_boolean = ecma_is_value_boolean (y); const bool is_y_number = ecma_is_value_number (y); const bool is_y_string = ecma_is_value_string (y); const bool is_y_object = ecma_is_value_object (y); const bool is_types_equal = ((is_x_undefined && is_y_undefined) || (is_x_null && is_y_null) || (is_x_boolean && is_y_boolean) || (is_x_number && is_y_number) || (is_x_string && is_y_string) || (is_x_object && is_y_object)); if (!is_types_equal) { return false; } else if (is_x_undefined || is_x_null) { return true; } else if (is_x_number) { ecma_number_t x_num = ecma_get_number_from_value (x); ecma_number_t y_num = ecma_get_number_from_value (y); bool is_x_nan = ecma_number_is_nan (x_num); bool is_y_nan = ecma_number_is_nan (y_num); if (is_x_nan || is_y_nan) { /* * If both are NaN * return true; * else * // one of the numbers is NaN, and another - is not * return false; */ return (is_x_nan && is_y_nan); } else if (ecma_number_is_zero (x_num) && ecma_number_is_zero (y_num) && ecma_number_is_negative (x_num) != ecma_number_is_negative (y_num)) { return false; } else { return (x_num == y_num); } } else if (is_x_string) { ecma_string_t *x_str_p = ecma_get_string_from_value (x); ecma_string_t *y_str_p = ecma_get_string_from_value (y); return ecma_compare_ecma_strings (x_str_p, y_str_p); } else if (is_x_boolean) { return (ecma_is_value_true (x) == ecma_is_value_true (y)); } else { JERRY_ASSERT (is_x_object); return (ecma_get_object_from_value (x) == ecma_get_object_from_value (y)); } } /* ecma_op_same_value */
/** * The Number.prototype object's 'toFixed' routine * * See also: * ECMA-262 v5, 15.7.4.5 * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_number_prototype_object_to_fixed (ecma_value_t this_arg, /**< this argument */ ecma_value_t arg) /**< routine's argument */ { ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); ECMA_TRY_CATCH (this_value, ecma_builtin_number_prototype_object_value_of (this_arg), ret_value); ecma_number_t this_num = *ecma_get_number_from_value (this_value); ECMA_OP_TO_NUMBER_TRY_CATCH (arg_num, arg, ret_value); /* 2. */ if (arg_num <= -1 || arg_num >= 21) { ret_value = ecma_raise_range_error (ECMA_ERR_MSG ("")); } else { /* 4. */ if (ecma_number_is_nan (this_num)) { ecma_string_t *nan_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_NAN); ret_value = ecma_make_string_value (nan_str_p); } else { bool is_negative = false; /* 6. */ if (ecma_number_is_negative (this_num)) { is_negative = true; this_num *= -1; } /* We handle infinities separately. */ if (ecma_number_is_infinity (this_num)) { ecma_string_t *infinity_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_INFINITY_UL); if (is_negative) { ecma_string_t *neg_str_p = ecma_new_ecma_string_from_utf8 ((const lit_utf8_byte_t *) "-", 1); ecma_string_t *neg_inf_str_p = ecma_concat_ecma_strings (neg_str_p, infinity_str_p); ecma_deref_ecma_string (infinity_str_p); ecma_deref_ecma_string (neg_str_p); ret_value = ecma_make_string_value (neg_inf_str_p); } else { ret_value = ecma_make_string_value (infinity_str_p); } } else { uint64_t digits = 0; int32_t num_digits = 0; int32_t exponent = 1; /* 1. */ int32_t frac_digits = ecma_number_to_int32 (arg_num); /* Get the parameters of the number if non-zero. */ if (!ecma_number_is_zero (this_num)) { ecma_number_to_decimal (this_num, &digits, &num_digits, &exponent); } digits = ecma_builtin_number_prototype_helper_round (digits, num_digits - exponent - frac_digits); /* 7. */ if (exponent > 21) { ret_value = ecma_builtin_number_prototype_object_to_string (this_arg, NULL, 0); } /* 8. */ else { /* Buffer that is used to construct the string. */ int buffer_size = (exponent > 0) ? exponent + frac_digits + 2 : frac_digits + 3; if (is_negative) { buffer_size++; } JERRY_ASSERT (buffer_size > 0); MEM_DEFINE_LOCAL_ARRAY (buff, buffer_size, lit_utf8_byte_t); lit_utf8_byte_t *p = buff; if (is_negative) { *p++ = '-'; } int8_t digit = 0; uint64_t s = 1; /* Calculate the magnitude of the number. This is used to get the digits from left to right. */ while (s <= digits) { s *= 10; } if (exponent <= 0) { /* Add leading zeros. */ *p++ = '0'; if (frac_digits != 0) { *p++ = '.'; } for (int i = 0; i < -exponent && i < frac_digits; i++) { *p++ = '0'; } /* Add significant digits. */ for (int i = -exponent; i < frac_digits; i++) { digit = 0; s /= 10; while (digits >= s && s > 0) { digits -= s; digit++; } *p = (lit_utf8_byte_t) ((lit_utf8_byte_t) digit + '0'); p++; } } else { /* Add significant digits. */ for (int i = 0; i < exponent; i++) { digit = 0; s /= 10; while (digits >= s && s > 0) { digits -= s; digit++; } *p = (lit_utf8_byte_t) ((lit_utf8_byte_t) digit + '0'); p++; } /* Add the decimal point after whole part. */ if (frac_digits != 0) { *p++ = '.'; } /* Add neccessary fracion digits. */ for (int i = 0; i < frac_digits; i++) { digit = 0; s /= 10; while (digits >= s && s > 0) { digits -= s; digit++; } *p = (lit_utf8_byte_t) ((lit_utf8_byte_t) digit + '0'); p++; } } JERRY_ASSERT (p - buff < buffer_size); /* String terminator. */ *p = 0; ecma_string_t *str = ecma_new_ecma_string_from_utf8 (buff, (lit_utf8_size_t) (p - buff)); ret_value = ecma_make_string_value (str); MEM_FINALIZE_LOCAL_ARRAY (buff); } } } } ECMA_OP_TO_NUMBER_FINALIZE (arg_num); ECMA_FINALIZE (this_value); return ret_value; } /* ecma_builtin_number_prototype_object_to_fixed */