/**
 * Promise routine: catch.
 *
 * See also: 25.4.5.1
 *
 * @return ecma value of a new promise object.
 *         Returned value must be freed with ecma_free_value.
 */
static ecma_value_t
ecma_builtin_promise_prototype_catch (ecma_value_t this_arg, /**< this argument */
                                      ecma_value_t on_rejected) /**< on_rejected function */
{
  return ecma_promise_then (this_arg,
                            ECMA_VALUE_UNDEFINED,
                            on_rejected);
} /* ecma_builtin_promise_prototype_catch */
/**
 * Promise routine: then.
 *
 * See also: 25.4.5.3
 *
 * @return ecma value of a new promise object.
 *         Returned value must be freed with ecma_free_value.
 */
static ecma_value_t
ecma_builtin_promise_prototype_then (ecma_value_t this_arg, /**< this argument */
                                     ecma_value_t on_fulfilled, /**< on_fulfilled function */
                                     ecma_value_t on_rejected) /**< on_rejected function */
{
  return ecma_promise_then (this_arg,
                            on_fulfilled,
                            on_rejected);
} /* ecma_builtin_promise_prototype_then */
/**
 * Runtime Semantics: PerformPromiseRace.
 *
 * See also:
 *         ES2015 25.4.4.3.1
 *
 * @return ecma value of the new promise.
 *         Returned value must be freed with ecma_free_value.
 */
inline static ecma_value_t
ecma_builtin_promise_do_race (ecma_value_t array, /**< the array for race */
                              ecma_value_t capability, /**< PromiseCapability record */
                              ecma_value_t ctor) /**< the caller of Promise.race */
{
  JERRY_ASSERT (ecma_is_value_object (capability)
                && ecma_is_value_object (array)
                && ecma_is_value_object (ctor));
  JERRY_ASSERT (ecma_get_object_builtin_id (ecma_get_object_from_value (ctor)) == ECMA_BUILTIN_ID_PROMISE);
  JERRY_ASSERT (ecma_get_object_type (ecma_get_object_from_value (array)) == ECMA_OBJECT_TYPE_ARRAY);

  ecma_value_t ret = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY);
  ecma_string_t *magic_string_length_p = ecma_new_ecma_length_string ();
  ecma_object_t *array_p = ecma_get_object_from_value (array);
  ecma_value_t len_value = ecma_op_object_get (array_p, magic_string_length_p);
  ecma_deref_ecma_string (magic_string_length_p);
  ecma_length_t len = (ecma_length_t) ecma_get_integer_from_value (len_value);
  ecma_fast_free_value (len_value);

  ecma_string_t *str_promise = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_PROMISE);
  ecma_string_t *str_resolve = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_RESOLVE);
  ecma_string_t *str_reject = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_REJECT);

  ecma_value_t resolve = ecma_op_object_get (ecma_get_object_from_value (capability),
                                             str_resolve);
  ecma_value_t reject = ecma_op_object_get (ecma_get_object_from_value (capability),
                                            str_reject);

  for (ecma_length_t index = 0; index <= len; index++)
  {
    /* b-d. */
    if (index == len)
    {
      ret = ecma_op_object_get (ecma_get_object_from_value (capability), str_promise);
      break;
    }

    /* e. */
    ecma_string_t *str_index = ecma_new_ecma_string_from_uint32 (index);
    ecma_value_t array_item = ecma_op_object_get (array_p, str_index);
    ecma_deref_ecma_string (str_index);

    /* h. */
    ecma_value_t next_promise = ecma_builtin_promise_resolve (ctor, array_item);
    ecma_free_value (array_item);

    /* i. */
    if (ECMA_IS_VALUE_ERROR (next_promise))
    {
      ret = next_promise;
      break;
    }

    /* j. */
    ecma_value_t then_result = ecma_promise_then (next_promise, resolve, reject);
    ecma_free_value (next_promise);

    /* k. */
    if (ECMA_IS_VALUE_ERROR (then_result))
    {
      ret = then_result;
      break;
    }

    ecma_free_value (then_result);
  }

  ecma_free_value (reject);
  ecma_free_value (resolve);
  ecma_deref_ecma_string (str_promise);
  ecma_deref_ecma_string (str_resolve);
  ecma_deref_ecma_string (str_reject);

  JERRY_ASSERT (!ecma_is_value_empty (ret));

  return ret;
} /* ecma_builtin_promise_do_race */