Implement other routines of Promise (#1729)

Add Promise.resolve, Promise.reject, Promise.race, Promise.all and
Promise.prototype.catch

Also it fixes the issue 1763

JerryScript-DCO-1.0-Signed-off-by: Zidong Jiang zidong.jiang@intel.com
This commit is contained in:
Zidong Jiang
2017-04-26 19:47:51 +08:00
committed by GitHub
parent 9d4123c3c4
commit 078f6e101d
20 changed files with 1044 additions and 138 deletions
+22 -15
View File
@@ -136,13 +136,15 @@ ecma_process_promise_reaction_job (void *obj_p) /**< the job to be operated */
ecma_job_promise_reaction_t *job_p = (ecma_job_promise_reaction_t *) obj_p;
ecma_object_t *reaction_p = ecma_get_object_from_value (job_p->reaction);
ecma_string_t *str_0 = ecma_new_ecma_string_from_uint32 (0);
ecma_string_t *str_1 = ecma_new_ecma_string_from_uint32 (1);
ecma_string_t *str_2 = ecma_new_ecma_string_from_uint32 (2);
/* 2. string '0' indicates the [[Capability]] of reaction. */
ecma_value_t capability = ecma_op_object_get (reaction_p, str_0);
/* 3. string '1' indicates the [[Handler]] of reaction. */
ecma_value_t handler = ecma_op_object_get (reaction_p, str_1);
ecma_string_t *str_capability = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_CAPABILITY);
ecma_string_t *str_handler = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_HANDLER);
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);
/* 2. */
ecma_value_t capability = ecma_op_object_get (reaction_p, str_capability);
/* 3. */
ecma_value_t handler = ecma_op_object_get (reaction_p, str_handler);
JERRY_ASSERT (ecma_is_value_boolean (handler) || ecma_op_is_callable (handler));
@@ -166,9 +168,13 @@ ecma_process_promise_reaction_job (void *obj_p) /**< the job to be operated */
if (ecma_is_value_false (handler) || ECMA_IS_VALUE_ERROR (handler_result))
{
/* 7. String '2' indicates [[Reject]] of Capability. */
handler_result = ecma_get_value_from_error_value (handler_result);
ecma_value_t reject = ecma_op_object_get (ecma_get_object_from_value (capability), str_2);
if (ECMA_IS_VALUE_ERROR (handler_result))
{
handler_result = ecma_get_value_from_error_value (handler_result);
}
/* 7. */
ecma_value_t reject = ecma_op_object_get (ecma_get_object_from_value (capability), str_reject);
JERRY_ASSERT (ecma_op_is_callable (reject));
@@ -180,8 +186,8 @@ ecma_process_promise_reaction_job (void *obj_p) /**< the job to be operated */
}
else
{
/* 8. String '1' indicates [[Resolve]] of Capability. */
ecma_value_t resolve = ecma_op_object_get (ecma_get_object_from_value (capability), str_1);
/* 8. */
ecma_value_t resolve = ecma_op_object_get (ecma_get_object_from_value (capability), str_resolve);
JERRY_ASSERT (ecma_op_is_callable (resolve));
@@ -195,9 +201,10 @@ ecma_process_promise_reaction_job (void *obj_p) /**< the job to be operated */
ecma_free_value (handler_result);
ecma_free_value (handler);
ecma_free_value (capability);
ecma_deref_ecma_string (str_0);
ecma_deref_ecma_string (str_1);
ecma_deref_ecma_string (str_2);
ecma_deref_ecma_string (str_capability);
ecma_deref_ecma_string (str_handler);
ecma_deref_ecma_string (str_resolve);
ecma_deref_ecma_string (str_reject);
ecma_free_promise_reaction_job (job_p);
return status;
@@ -344,54 +344,55 @@ ecma_call_builtin_executor (ecma_object_t *executor_p, /**< the executor object
ecma_value_t resolve_func, /**< the resolve function */
ecma_value_t reject_func) /**< the reject function */
{
ecma_string_t *str_0 = ecma_new_ecma_string_from_uint32 (0);
ecma_string_t *str_1 = ecma_new_ecma_string_from_uint32 (1);
ecma_string_t *str_2 = ecma_new_ecma_string_from_uint32 (2);
/* 2. String '0' indicates [[Capability]] of the executor. */
ecma_value_t capability = ecma_op_object_get (executor_p, str_0);
/* 3. String '1' indicates [[Resolve]] of the capability. */
ecma_value_t resolve = ecma_op_object_get (ecma_get_object_from_value (capability), str_1);
ecma_string_t *str_capability = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_CAPABILITY);
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);
/* 2. */
ecma_value_t capability = ecma_op_object_get (executor_p, str_capability);
/* 3. */
ecma_value_t resolve = ecma_op_object_get (ecma_get_object_from_value (capability), str_resolve);
if (resolve != ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED))
{
ecma_free_value (resolve);
ecma_free_value (capability);
ecma_deref_ecma_string (str_0);
ecma_deref_ecma_string (str_1);
ecma_deref_ecma_string (str_2);
ecma_deref_ecma_string (str_capability);
ecma_deref_ecma_string (str_resolve);
ecma_deref_ecma_string (str_reject);
return ecma_raise_type_error (ECMA_ERR_MSG ("'resolve' function should be undefined."));
}
/* 4. String '2' indicates [[Reject]] of the capability. */
ecma_value_t reject = ecma_op_object_get (ecma_get_object_from_value (capability), str_2);
/* 4. */
ecma_value_t reject = ecma_op_object_get (ecma_get_object_from_value (capability), str_reject);
if (reject != ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED))
{
ecma_free_value (reject);
ecma_free_value (capability);
ecma_deref_ecma_string (str_0);
ecma_deref_ecma_string (str_1);
ecma_deref_ecma_string (str_2);
ecma_deref_ecma_string (str_capability);
ecma_deref_ecma_string (str_resolve);
ecma_deref_ecma_string (str_reject);
return ecma_raise_type_error (ECMA_ERR_MSG ("'reject' function should be undefined."));
}
/* 5. */
ecma_op_object_put (ecma_get_object_from_value (capability),
str_1,
str_resolve,
resolve_func,
false);
/* 6. */
ecma_op_object_put (ecma_get_object_from_value (capability),
str_2,
str_reject,
reject_func,
false);
ecma_free_value (capability);
ecma_deref_ecma_string (str_0);
ecma_deref_ecma_string (str_1);
ecma_deref_ecma_string (str_2);
ecma_deref_ecma_string (str_capability);
ecma_deref_ecma_string (str_resolve);
ecma_deref_ecma_string (str_reject);
return ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
} /* ecma_call_builtin_executor */
@@ -558,29 +559,30 @@ ecma_promise_new_capability (void)
{
/* 3. */
ecma_object_t *capability_p = ecma_op_create_object_object_noarg ();
ecma_string_t *str_0 = ecma_new_ecma_string_from_uint32 (0);
ecma_string_t *str_capability = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_CAPABILITY);
ecma_string_t *str_promise = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_PROMISE);
/* 4. */
ecma_object_t *executor_p;
executor_p = ecma_op_create_object_object_noarg ();
ecma_value_t executor = ecma_make_object_value (executor_p);
/* 5. String '0' here indicates the [[Capability]] of executor. */
/* 5. */
ecma_op_object_put (executor_p,
str_0,
str_capability,
ecma_make_object_value (capability_p),
false);
/* 6. */
ecma_value_t promise = ecma_op_create_promise_object (executor, false);
/* 10. String '0' here indicates the [[Promise]] of Capability. */
/* 10. */
ecma_op_object_put (capability_p,
str_0,
str_promise,
promise,
false);
ecma_deref_object (executor_p);
ecma_deref_ecma_string (str_0);
ecma_deref_ecma_string (str_promise);
ecma_deref_ecma_string (str_capability);
/* 7. */
if (ECMA_IS_VALUE_ERROR (promise))
{
@@ -590,10 +592,10 @@ ecma_promise_new_capability (void)
}
ecma_free_value (promise);
/* 8. str '1' indicates [[Resolve]] of Capability. */
ecma_string_t *str_1 = ecma_new_ecma_string_from_uint32 (1);
ecma_value_t resolve = ecma_op_object_get (capability_p, str_1);
ecma_deref_ecma_string (str_1);
/* 8. */
ecma_string_t *str_resolve = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_RESOLVE);
ecma_value_t resolve = ecma_op_object_get (capability_p, str_resolve);
ecma_deref_ecma_string (str_resolve);
if (!ecma_op_is_callable (resolve))
{
@@ -603,10 +605,10 @@ ecma_promise_new_capability (void)
}
ecma_free_value (resolve);
/* 9. str '2' indicates [[Reject]] of Capability. */
ecma_string_t *str_2 = ecma_new_ecma_string_from_uint32 (2);
ecma_value_t reject = ecma_op_object_get (capability_p, str_2);
ecma_deref_ecma_string (str_2);
/* 9. */
ecma_string_t *str_reject = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_REJECT);
ecma_value_t reject = ecma_op_object_get (capability_p, str_reject);
ecma_deref_ecma_string (str_reject);
if (!ecma_op_is_callable (reject))
{
@@ -629,14 +631,15 @@ ecma_promise_new_capability (void)
* @return ecma value of the new promise object
* Returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_promise_then (ecma_value_t promise, /**< the promise which call 'then' */
ecma_value_t on_fulfilled, /**< on_fulfilled function */
ecma_value_t on_rejected, /**< on_rejected function */
ecma_value_t result_capability) /**< promise capability */
static ecma_value_t
ecma_promise_do_then (ecma_value_t promise, /**< the promise which call 'then' */
ecma_value_t on_fulfilled, /**< on_fulfilled function */
ecma_value_t on_rejected, /**< on_rejected function */
ecma_value_t result_capability) /**< promise capability */
{
ecma_string_t *str_0 = ecma_new_ecma_string_from_uint32 (0);
ecma_string_t *str_1 = ecma_new_ecma_string_from_uint32 (1);
ecma_string_t *str_capability = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_CAPABILITY);
ecma_string_t *str_handler = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_HANDLER);
ecma_string_t *str_promise = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_PROMISE);
/* 3. boolean true indicates "indentity" */
if (!ecma_op_is_callable (on_fulfilled))
@@ -650,24 +653,24 @@ ecma_promise_then (ecma_value_t promise, /**< the promise which call 'then' */
on_rejected = ecma_make_boolean_value (false);
}
/* 5-6. String '0' indicates [[Capability]] of a PromiseReaction, '1' indicates [[Handler]]. */
/* 5-6. */
ecma_object_t *fulfill_reaction_p = ecma_op_create_object_object_noarg ();
ecma_object_t *reject_reaction_p = ecma_op_create_object_object_noarg ();
ecma_op_object_put (fulfill_reaction_p,
str_0,
str_capability,
result_capability,
false);
ecma_op_object_put (fulfill_reaction_p,
str_1,
str_handler,
on_fulfilled,
false);
ecma_op_object_put (reject_reaction_p,
str_0,
str_capability,
result_capability,
false);
ecma_op_object_put (reject_reaction_p,
str_1,
str_handler,
on_rejected,
false);
@@ -700,13 +703,45 @@ ecma_promise_then (ecma_value_t promise, /**< the promise which call 'then' */
ecma_free_value (reason);
}
/* 10. String '0' indicates [[Promise]] of a Capability. */
ecma_value_t ret = ecma_op_object_get (ecma_get_object_from_value (result_capability), str_0);
/* 10. */
ecma_value_t ret = ecma_op_object_get (ecma_get_object_from_value (result_capability), str_promise);
ecma_deref_object (fulfill_reaction_p);
ecma_deref_object (reject_reaction_p);
ecma_deref_ecma_string (str_0);
ecma_deref_ecma_string (str_1);
ecma_deref_ecma_string (str_capability);
ecma_deref_ecma_string (str_handler);
ecma_deref_ecma_string (str_promise);
return ret;
} /* ecma_promise_do_then */
/**
* The common function for ecma_builtin_promise_prototype_then
* and ecma_builtin_promise_prototype_catch.
*
* @return ecma value of a new promise object.
* Returned value must be freed with ecma_free_value.
*/
ecma_value_t
ecma_promise_then (ecma_value_t promise, /**< the promise which call 'then' */
ecma_value_t on_fulfilled, /**< on_fulfilled function */
ecma_value_t on_rejected) /**< on_rejected function */
{
ecma_object_t *obj = ecma_get_object_from_value (promise);
if (!ecma_is_promise (obj))
{
return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not a Promise."));
}
ecma_value_t result_capability = ecma_promise_new_capability ();
if (ECMA_IS_VALUE_ERROR (result_capability))
{
return result_capability;
}
ecma_value_t ret = ecma_promise_do_then (promise, on_fulfilled, on_rejected, result_capability);
ecma_free_value (result_capability);
return ret;
} /* ecma_promise_then */
@@ -58,6 +58,23 @@ typedef struct
ecma_collection_header_t *reject_reactions; /**< list of PromiseRejectReactions */
} ecma_promise_object_t;
/**
* Use symbolic constant to represent the internal property name of
* promise related structures.
*/
typedef enum
{
ECMA_PROMISE_PROPERTY_PROMISE, /**< [[Promise]] property */
ECMA_PROMISE_PROPERTY_RESOLVE, /**< [[Resolve]] property */
ECMA_PROMISE_PROPERTY_REJECT, /**< [[Reject]] property */
ECMA_PROMISE_PROPERTY_CAPABILITY, /**< [[Capability]] property */
ECMA_PROMISE_PROPERTY_HANDLER, /**< [[Handler]] property */
ECMA_PROMISE_PROPERTY_ALREADY_CALLED, /**< [[AlreadyCalled]] property */
ECMA_PROMISE_PROPERTY_INDEX, /**< [[Index]] property */
ECMA_PROMISE_PROPERTY_VALUE, /**< [[Values]] property */
ECMA_PROMISE_PROPERTY_REMAINING_ELEMENT /**< [[RemainingElement]] property */
} ecma_promise_property_symbolic_constant_t;
bool ecma_is_promise (ecma_object_t *obj_p);
ecma_value_t ecma_promise_get_result (ecma_object_t *obj_p);
void ecma_promise_set_result (ecma_object_t *obj_p, ecma_value_t result);
@@ -72,8 +89,8 @@ ecma_value_t ecma_promise_new_capability (void);
ecma_value_t
ecma_promise_then (ecma_value_t promise,
ecma_value_t on_fulfilled,
ecma_value_t on_rejected,
ecma_value_t result_capability);
ecma_value_t on_rejected);
/**
* @}
* @}