예제 #1
0
/**
 * 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 */
예제 #2
0
/**
 * 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 */
예제 #3
0
/**
 * 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 */
예제 #4
0
/**
 * 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 */
예제 #5
0
/**
 * 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 */
예제 #6
0
/**
 * 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 */
예제 #12
0
/**
 * 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 */
예제 #13
0
/**
 * 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 */
예제 #15
0
/**
 * 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 */
예제 #16
0
/**
 * 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 */