From 078f6e101dad0a87ce4795e4dec0e46a022755b0 Mon Sep 17 00:00:00 2001 From: Zidong Jiang Date: Wed, 26 Apr 2017 19:47:51 +0800 Subject: [PATCH] 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 --- .../ecma-builtin-promise-prototype.c | 44 +- .../ecma-builtin-promise-prototype.inc.h | 1 + .../builtin-objects/ecma-builtin-promise.c | 612 ++++++++++++++++++ .../ecma-builtin-promise.inc.h | 8 + jerry-core/ecma/operations/ecma-jobqueue.c | 37 +- .../ecma/operations/ecma-promise-object.c | 137 ++-- .../ecma/operations/ecma-promise-object.h | 21 +- jerry-core/lit/lit-magic-strings.inc.h | 17 + jerry-core/lit/lit-magic-strings.ini | 5 + .../es2015/25/25.04/25.04.04/25.04.04-001.js | 5 +- .../es2015/25/25.04/25.04.04/25.04.04-002.js | 27 +- .../es2015/25/25.04/25.04.04/25.04.04-003.js | 26 +- .../es2015/25/25.04/25.04.04/25.04.04-004.js | 39 +- .../es2015/25/25.04/25.04.04/25.04.04-005.js | 52 ++ .../es2015/25/25.04/25.04.05/25.04.05-001.js | 16 + .../es2015/25/25.04/25.04.05/25.04.05-002.js | 36 ++ .../es2015/25/25.04/25.04.05/25.04.05-003.js | 36 ++ .../es2015/25/25.04/25.04.05/25.04.05-004.js | 26 + .../es2015/25/25.04/25.04.05/25.04.05-005.js | 22 + .../es2015/regression-test-issue-1763.js | 15 + 20 files changed, 1044 insertions(+), 138 deletions(-) create mode 100644 tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-005.js create mode 100644 tests/jerry-test-suite/es2015/25/25.04/25.04.05/25.04.05-001.js create mode 100644 tests/jerry-test-suite/es2015/25/25.04/25.04.05/25.04.05-002.js create mode 100644 tests/jerry-test-suite/es2015/25/25.04/25.04.05/25.04.05-003.js create mode 100644 tests/jerry-test-suite/es2015/25/25.04/25.04.05/25.04.05-004.js create mode 100644 tests/jerry-test-suite/es2015/25/25.04/25.04.05/25.04.05-005.js create mode 100644 tests/jerry/es2015/regression-test-issue-1763.js diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-promise-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-promise-prototype.c index caefd386b..d915a2135 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-promise-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-promise-prototype.c @@ -13,9 +13,7 @@ * limitations under the License. */ -#include "ecma-exceptions.h" #include "ecma-globals.h" -#include "ecma-helpers.h" #include "ecma-promise-object.h" #ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN @@ -42,34 +40,36 @@ * * See also: 25.4.5.3 * - * @return ecma value of a new promise object - * Returned value must be freed with ecma_free_value + * @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 */ { - ecma_object_t *obj = ecma_get_object_from_value (this_arg); - - 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_then (this_arg, on_fulfilled, on_rejected, result_capability); - ecma_free_value (result_capability); - - return ret; + return ecma_promise_then (this_arg, + on_fulfilled, + on_rejected); } /* ecma_builtin_promise_prototype_then */ +/** + * 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_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED), + on_rejected); +} /* ecma_builtin_promise_prototype_catch */ + /** * @} * @} diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-promise-prototype.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-promise-prototype.inc.h index 3e750e7c5..9e7029704 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-promise-prototype.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-promise-prototype.inc.h @@ -29,6 +29,7 @@ NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, ECMA_PROPERTY_FLAG_WRITABLE) ROUTINE (LIT_MAGIC_STRING_THEN, ecma_builtin_promise_prototype_then, 2, 2) +ROUTINE (LIT_MAGIC_STRING_CATCH, ecma_builtin_promise_prototype_catch, 1, 1) #endif /* !CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c b/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c index 47a6bf2b8..24cb4de00 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c @@ -13,9 +13,12 @@ * limitations under the License. */ +#include "ecma-array-object.h" #include "ecma-exceptions.h" #include "ecma-function-object.h" +#include "ecma-gc.h" #include "ecma-globals.h" +#include "ecma-number-object.h" #include "ecma-promise-object.h" #ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN @@ -37,6 +40,615 @@ * @{ */ +/** + * The common function for 'reject' and 'resolve'. + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_promise_reject_or_resolve (ecma_value_t this_arg, /**< "this" argument */ + ecma_value_t argument, /**< argument for reject or resolve */ + bool is_resolve) /**< whether it is for resolve routine */ +{ + if (!ecma_is_value_object (this_arg)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not an object.")); + } + + uint8_t builtin_id = ecma_get_object_builtin_id (ecma_get_object_from_value (this_arg)); + + if (builtin_id != ECMA_BUILTIN_ID_PROMISE) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not the Promise constructor.")); + } + + if (is_resolve + && ecma_is_value_object (argument) + && ecma_is_promise (ecma_get_object_from_value (argument))) + { + return ecma_copy_value (argument); + } + + + ecma_value_t capability = ecma_promise_new_capability (); + + if (ECMA_IS_VALUE_ERROR (capability)) + { + return capability; + } + + ecma_string_t *str; + + if (is_resolve) + { + str = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_RESOLVE); + } + else + { + str = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_REJECT); + } + + ecma_value_t func = ecma_op_object_get (ecma_get_object_from_value (capability), str); + ecma_deref_ecma_string (str); + + ecma_value_t call_ret = ecma_op_function_call (ecma_get_object_from_value (func), + ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED), + &argument, + 1); + + ecma_free_value (func); + + if (ECMA_IS_VALUE_ERROR (call_ret)) + { + return call_ret; + } + + ecma_free_value (call_ret); + + ecma_string_t *str_promise = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_PROMISE); + ecma_value_t promise_new = ecma_op_object_get (ecma_get_object_from_value (capability), str_promise); + ecma_deref_ecma_string (str_promise); + ecma_free_value (capability); + + return promise_new; +} /* ecma_builtin_promise_reject_or_resolve */ + +/** + * Reject the promise if the value is error. + * + * See also: + * ES2015 25.4.1.1.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_reject_abrupt (ecma_value_t abrupt_value, + ecma_value_t capability) +{ + ecma_value_t reason = ecma_get_value_from_error_value (abrupt_value); + ecma_string_t *str_reject = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_REJECT); + ecma_value_t reject = ecma_op_object_get (ecma_get_object_from_value (capability), str_reject); + ecma_deref_ecma_string (str_reject); + + ecma_value_t call_ret = ecma_op_function_call (ecma_get_object_from_value (reject), + ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED), + &reason, + 1); + ecma_free_value (reject); + + if (ECMA_IS_VALUE_ERROR (call_ret)) + { + return call_ret; + } + + ecma_free_value (call_ret); + + ecma_string_t *str_promise = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_PROMISE); + ecma_value_t promise_new = ecma_op_object_get (ecma_get_object_from_value (capability), str_promise); + ecma_deref_ecma_string (str_promise); + + return promise_new; +} /* ecma_builtin_promise_reject_abrupt */ + +/** + * The Promise.reject routine. + * + * See also: + * ES2015 25.4.4.4 + * + * @return ecma value of the new promise. + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_promise_reject (ecma_value_t this_arg, /**< 'this' argument */ + ecma_value_t reason) /**< the reason for reject */ +{ + return ecma_builtin_promise_reject_or_resolve (this_arg, reason, false); +} /* ecma_builtin_promise_reject */ + +/** + * The Promise.resolve routine. + * + * See also: + * ES2015 25.4.4.5 + * + * @return ecma value of the new promise. + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_promise_resolve (ecma_value_t this_arg, /**< 'this' argument */ + ecma_value_t argument) /**< the argument for resolve */ +{ + return ecma_builtin_promise_reject_or_resolve (this_arg, argument, true); +} /* ecma_builtin_promise_resolve */ + +/** + * 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 */ + +/** + * Helper function for increase or decrease the remaining count. + * + * @return the current remaining count after increase or decrease. + */ +static ecma_length_t +ecma_builtin_promise_remaining_inc_or_dec (ecma_value_t remaining, /**< the remaining count */ + bool is_inc) /**< whether to increase the count */ +{ + JERRY_ASSERT (ecma_is_value_object (remaining)); + + ecma_object_t *remaining_p = ecma_get_object_from_value (remaining); + ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) remaining_p; + + JERRY_ASSERT (ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_NUMBER_UL); + + JERRY_ASSERT (ecma_is_value_integer_number (ext_object_p->u.class_prop.u.value)); + + ecma_length_t current = (ecma_length_t) ecma_get_integer_from_value (ext_object_p->u.class_prop.u.value); + + if (is_inc) + { + current++; + } + else + { + current--; + } + + ext_object_p->u.class_prop.u.value = ecma_make_uint32_value (current); + + return current; +} /* ecma_builtin_promise_remaining_inc_or_dec */ + +/** + * Native handler for Promise.all Resolve Element Function. + * + * See also: + * ES2015 25.4.4.1.2 + * + * @return ecma value of undefined. + */ +static ecma_value_t +ecma_builtin_promise_all_handler (const ecma_value_t function, /**< the function itself */ + const ecma_value_t this, /**< this_arg of the function */ + const ecma_value_t argv[], /**< argument list */ + const ecma_length_t argc) /**< argument number */ +{ + JERRY_UNUSED (this); + JERRY_UNUSED (argc); + + ecma_value_t ret = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); + /* 1. */ + ecma_object_t *function_p = ecma_get_object_from_value (function); + ecma_string_t *str_already_called = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_ALREADY_CALLED); + ecma_value_t already_called = ecma_op_object_get (function_p, str_already_called); + + JERRY_ASSERT (ecma_is_value_boolean (already_called)); + + /* 2. */ + if (ecma_is_value_true (already_called)) + { + ecma_fast_free_value (already_called); + ecma_deref_ecma_string (str_already_called); + + return ret; + } + + /* 3. */ + ecma_op_object_put (function_p, + str_already_called, + ecma_make_boolean_value (true), + false); + + ecma_string_t *str_index = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_INDEX); + ecma_string_t *str_value = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_VALUE); + ecma_string_t *str_capability = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_CAPABILITY); + ecma_string_t *str_remaining = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_REMAINING_ELEMENT); + + /* 4-7. */ + ecma_value_t index_val = ecma_op_object_get (function_p, str_index); + ecma_value_t value_array = ecma_op_object_get (function_p, str_value); + ecma_value_t capability = ecma_op_object_get (function_p, str_capability); + ecma_value_t remaining = ecma_op_object_get (function_p, str_remaining); + + JERRY_ASSERT (ecma_is_value_integer_number (index_val)); + + /* 8. */ + ecma_string_t *index_str = ecma_new_ecma_string_from_uint32 ((uint32_t) ecma_get_integer_from_value (index_val)); + + ecma_op_object_put (ecma_get_object_from_value (value_array), + index_str, + argv[0], + false); + ecma_deref_ecma_string (index_str); + + /* 9-10. */ + if (ecma_builtin_promise_remaining_inc_or_dec (remaining, false) == 0) + { + ecma_string_t *str_resolve = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_RESOLVE); + ecma_value_t resolve = ecma_op_object_get (ecma_get_object_from_value (capability), + str_resolve); + ecma_deref_ecma_string (str_resolve); + ret = ecma_op_function_call (ecma_get_object_from_value (resolve), + ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED), + &value_array, + 1); + ecma_free_value (resolve); + } + + ecma_free_value (remaining); + ecma_free_value (capability); + ecma_free_value (value_array); + ecma_fast_free_value (index_val); + ecma_fast_free_value (already_called); + ecma_deref_ecma_string (str_already_called); + ecma_deref_ecma_string (str_index); + ecma_deref_ecma_string (str_value); + ecma_deref_ecma_string (str_capability); + ecma_deref_ecma_string (str_remaining); + + return ret; +} /* ecma_builtin_promise_all_handler */ + +/** + * Runtime Semantics: PerformPromiseAll. + * + * See also: + * ES2015 25.4.4.1.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_all (ecma_value_t array, /**< the array for all */ + 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_string_t *str_already_called = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_ALREADY_CALLED); + ecma_string_t *str_index = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_INDEX); + ecma_string_t *str_value = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_VALUE); + ecma_string_t *str_capability = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_CAPABILITY); + ecma_string_t *str_remaining = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_REMAINING_ELEMENT); + + ecma_value_t undefined_val = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); + /* String '1' indicates [[Resolve]] and '2' indicates [[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); + /* 3. */ + ecma_value_t result_array_length_val = ecma_make_uint32_value (0); + ecma_value_t value_array = ecma_op_create_array_object (&result_array_length_val, 1, true); + ecma_free_value (result_array_length_val); + /* 4. */ + ecma_value_t remaining = ecma_op_create_number_object (ecma_make_integer_value (1)); + /* 5. */ + ecma_length_t index = 0; + + /* 6 */ + while (true) + { + JERRY_ASSERT (index <= len); + /* d. */ + if (index == len) + { + /* ii. */ + if (ecma_builtin_promise_remaining_inc_or_dec (remaining, false) == 0) + { + /* iii. */ + ecma_value_t resolve_ret = ecma_op_function_call (ecma_get_object_from_value (resolve), + ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED), + &value_array, + 1); + + if (ECMA_IS_VALUE_ERROR (resolve_ret)) + { + ret = resolve_ret; + break; + } + } + + /* iv. */ + ret = ecma_op_object_get (ecma_get_object_from_value (capability), str_promise); + break; + } + + /* e. h. */ + ecma_string_t *index_str = ecma_new_ecma_string_from_uint32 (index); + ecma_value_t array_item = ecma_op_object_get (array_p, index_str); + ecma_op_object_put (ecma_get_object_from_value (value_array), + index_str, + undefined_val, + false); + ecma_deref_ecma_string (index_str); + /* i. */ + ecma_value_t next_promise = ecma_builtin_promise_resolve (ctor, array_item); + ecma_free_value (array_item); + + /* j. */ + if (ECMA_IS_VALUE_ERROR (next_promise)) + { + ret = next_promise; + break; + } + + /* k. */ + ecma_object_t *res_ele_p; + res_ele_p = ecma_op_create_external_function_object ((ecma_external_pointer_t) ecma_builtin_promise_all_handler); + /* l. */ + ecma_op_object_put (res_ele_p, + str_already_called, + ecma_make_boolean_value (false), + false); + /* m. */ + ecma_op_object_put (res_ele_p, + str_index, + ecma_make_uint32_value (index), + false); + /* n. */ + ecma_op_object_put (res_ele_p, + str_value, + value_array, + false); + /* o. */ + ecma_op_object_put (res_ele_p, + str_capability, + capability, + false); + /* p. */ + ecma_op_object_put (res_ele_p, + str_remaining, + remaining, + false); + + /* q. */ + ecma_builtin_promise_remaining_inc_or_dec (remaining, true); + /* r. */ + ecma_value_t then_result = ecma_promise_then (next_promise, + ecma_make_object_value (res_ele_p), + reject); + ecma_deref_object (res_ele_p); + ecma_free_value (next_promise); + + /* s. */ + if (ECMA_IS_VALUE_ERROR (then_result)) + { + ret = then_result; + break; + } + + ecma_free_value (then_result); + index ++; + } + + ecma_free_value (reject); + ecma_free_value (resolve); + ecma_free_value (remaining); + ecma_free_value (value_array); + ecma_deref_ecma_string (str_already_called); + ecma_deref_ecma_string (str_index); + ecma_deref_ecma_string (str_value); + ecma_deref_ecma_string (str_capability); + ecma_deref_ecma_string (str_remaining); + ecma_deref_ecma_string (str_resolve); + ecma_deref_ecma_string (str_reject); + ecma_deref_ecma_string (str_promise); + + JERRY_ASSERT (!ecma_is_value_empty (ret)); + + return ret; +} /* ecma_builtin_promise_do_all */ + +/** + * The common function for both Promise.race and Promise.all. + * + * @return ecma value of the new promise. + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_promise_race_or_all (ecma_value_t this_arg, /**< 'this' argument */ + ecma_value_t array, /**< the items to be resolved */ + bool is_race) /**< indicates whether it is race function */ +{ + if (!ecma_is_value_object (this_arg)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not an object.")); + } + + uint8_t builtin_id = ecma_get_object_builtin_id (ecma_get_object_from_value (this_arg)); + + if (builtin_id != ECMA_BUILTIN_ID_PROMISE) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not the Promise constructor.")); + } + + ecma_value_t capability = ecma_promise_new_capability (); + ecma_value_t ret = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); + + if (!ecma_is_value_object (array) + || ecma_get_object_type (ecma_get_object_from_value (array)) != ECMA_OBJECT_TYPE_ARRAY) + { + ecma_value_t error = ecma_raise_type_error (ECMA_ERR_MSG ("Second argument is not an array.")); + ret = ecma_builtin_promise_reject_abrupt (error, capability); + ecma_free_value (error); + ecma_free_value (capability); + + return ret; + } + + if (is_race) + { + ret = ecma_builtin_promise_do_race (array, capability, this_arg); + } + else + { + ret = ecma_builtin_promise_do_all (array, capability, this_arg); + } + + if (ECMA_IS_VALUE_ERROR (ret)) + { + ret = ecma_get_value_from_error_value (ret); + } + + ecma_free_value (capability); + + return ret; +} /* ecma_builtin_promise_race_or_all */ + +/** + * The Promise.race routine. + * + * See also: + * ES2015 25.4.4.3 + * + * @return ecma value of the new promise. + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_promise_race (ecma_value_t this_arg, /**< 'this' argument */ + ecma_value_t array) /**< the items to be resolved */ +{ + return ecma_builtin_promise_race_or_all (this_arg, array, true); +} /* ecma_builtin_promise_race */ + +/** + * The Promise.all routine. + * + * See also: + * ES2015 25.4.4.1 + * + * @return ecma value of the new promise. + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_promise_all (ecma_value_t this_arg, /**< 'this' argument */ + ecma_value_t array) /**< the items to be resolved */ +{ + return ecma_builtin_promise_race_or_all (this_arg, array, false); +} /* ecma_builtin_promise_all */ + /** * Handle calling [[Call]] of built-in Promise object. * diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-promise.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-promise.inc.h index 9e77f1e7e..ade0a8f39 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-promise.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-promise.inc.h @@ -19,6 +19,8 @@ #include "ecma-builtin-helpers-macro-defines.inc.h" +#ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN + /* Number properties: * (property name, number value, writable, enumerable, configurable) */ @@ -35,5 +37,11 @@ OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE, /* Routine properties: * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ +ROUTINE (LIT_MAGIC_STRING_REJECT, ecma_builtin_promise_reject, 1, 1) +ROUTINE (LIT_MAGIC_STRING_RESOLVE, ecma_builtin_promise_resolve, 1, 1) +ROUTINE (LIT_MAGIC_STRING_RACE, ecma_builtin_promise_race, 1, 1) +ROUTINE (LIT_MAGIC_STRING_ALL, ecma_builtin_promise_all, 1, 1) + +#endif /* !CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */ #include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/operations/ecma-jobqueue.c b/jerry-core/ecma/operations/ecma-jobqueue.c index 5189cd15e..afe8dcb61 100644 --- a/jerry-core/ecma/operations/ecma-jobqueue.c +++ b/jerry-core/ecma/operations/ecma-jobqueue.c @@ -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; diff --git a/jerry-core/ecma/operations/ecma-promise-object.c b/jerry-core/ecma/operations/ecma-promise-object.c index 9e67f0051..0dc43ca27 100644 --- a/jerry-core/ecma/operations/ecma-promise-object.c +++ b/jerry-core/ecma/operations/ecma-promise-object.c @@ -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 */ diff --git a/jerry-core/ecma/operations/ecma-promise-object.h b/jerry-core/ecma/operations/ecma-promise-object.h index b11c19e3e..9873f2657 100644 --- a/jerry-core/ecma/operations/ecma-promise-object.h +++ b/jerry-core/ecma/operations/ecma-promise-object.h @@ -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); + /** * @} * @} diff --git a/jerry-core/lit/lit-magic-strings.inc.h b/jerry-core/lit/lit-magic-strings.inc.h index 957a4e036..d166a4462 100644 --- a/jerry-core/lit/lit-magic-strings.inc.h +++ b/jerry-core/lit/lit-magic-strings.inc.h @@ -63,6 +63,11 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_UTC_U, "UTC") #endif #if !defined (CONFIG_DISABLE_MATH_BUILTIN) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ABS, "abs") +#endif +#if !defined (CONFIG_DISABLE_ES2015_PROMISE_BUILTIN) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ALL, "all") +#endif +#if !defined (CONFIG_DISABLE_MATH_BUILTIN) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_COS, "cos") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_EXP, "exp") #endif @@ -130,6 +135,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_NULL, "null") #if !defined (CONFIG_DISABLE_ARRAY_BUILTIN) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_PUSH, "push") #endif +#if !defined (CONFIG_DISABLE_ES2015_PROMISE_BUILTIN) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_RACE, "race") +#endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SEAL, "seal") #if !defined (CONFIG_DISABLE_ARRAY_BUILTIN) \ || !defined (CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN) @@ -161,6 +169,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_APPLY, "apply") #if !defined (CONFIG_DISABLE_MATH_BUILTIN) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ATAN2, "atan2") #endif +#if !defined (CONFIG_DISABLE_ES2015_PROMISE_BUILTIN) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CATCH, "catch") +#endif #if !defined (CONFIG_DISABLE_ARRAY_BUILTIN) \ || !defined (CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_EVERY, "every") @@ -244,6 +255,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_RANDOM, "random") || !defined (CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_REDUCE, "reduce") #endif +#if !defined (CONFIG_DISABLE_ES2015_PROMISE_BUILTIN) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_REJECT, "reject") +#endif #if !defined (CONFIG_DISABLE_REGEXP_BUILTIN) && !defined (CONFIG_DISABLE_STRING_BUILTIN) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SEARCH, "search") #endif @@ -294,6 +308,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_MESSAGE, "message") #if !defined (CONFIG_DISABLE_REGEXP_BUILTIN) && !defined (CONFIG_DISABLE_STRING_BUILTIN) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_REPLACE, "replace") #endif +#if !defined (CONFIG_DISABLE_ES2015_PROMISE_BUILTIN) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_RESOLVE, "resolve") +#endif #if !defined (CONFIG_DISABLE_ARRAY_BUILTIN) \ || !defined (CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_REVERSE, "reverse") diff --git a/jerry-core/lit/lit-magic-strings.ini b/jerry-core/lit/lit-magic-strings.ini index 2fa3320e3..0a2535b8e 100644 --- a/jerry-core/lit/lit-magic-strings.ini +++ b/jerry-core/lit/lit-magic-strings.ini @@ -47,6 +47,7 @@ LIT_MAGIC_STRING_LN2_U = "LN2" LIT_MAGIC_STRING_NAN = "NaN" LIT_MAGIC_STRING_UTC_U = "UTC" LIT_MAGIC_STRING_ABS = "abs" +LIT_MAGIC_STRING_ALL = "all" LIT_MAGIC_STRING_COS = "cos" LIT_MAGIC_STRING_EXP = "exp" LIT_MAGIC_STRING_GET = "get" @@ -80,6 +81,7 @@ LIT_MAGIC_STRING_KEYS = "keys" LIT_MAGIC_STRING_NAME = "name" LIT_MAGIC_STRING_NULL = "null" LIT_MAGIC_STRING_PUSH = "push" +LIT_MAGIC_STRING_RACE = "race" LIT_MAGIC_STRING_SEAL = "seal" LIT_MAGIC_STRING_SOME = "some" LIT_MAGIC_STRING_SORT = "sort" @@ -94,6 +96,7 @@ LIT_MAGIC_STRING_LOG2E_U = "LOG2E" LIT_MAGIC_STRING_SQRT2_U = "SQRT2" LIT_MAGIC_STRING_APPLY = "apply" LIT_MAGIC_STRING_ATAN2 = "atan2" +LIT_MAGIC_STRING_CATCH = "catch" LIT_MAGIC_STRING_EVERY = "every" LIT_MAGIC_STRING_FALSE = "false" LIT_MAGIC_STRING_FLOOR = "floor" @@ -130,6 +133,7 @@ LIT_MAGIC_STRING_NUMBER = "number" LIT_MAGIC_STRING_OBJECT = "object" LIT_MAGIC_STRING_RANDOM = "random" LIT_MAGIC_STRING_REDUCE = "reduce" +LIT_MAGIC_STRING_REJECT = "reject" LIT_MAGIC_STRING_SEARCH = "search" LIT_MAGIC_STRING_SOURCE = "source" LIT_MAGIC_STRING_SPLICE = "splice" @@ -149,6 +153,7 @@ LIT_MAGIC_STRING_INDEX_OF_UL = "indexOf" LIT_MAGIC_STRING_IS_ARRAY_UL = "isArray" LIT_MAGIC_STRING_MESSAGE = "message" LIT_MAGIC_STRING_REPLACE = "replace" +LIT_MAGIC_STRING_RESOLVE = "resolve" LIT_MAGIC_STRING_REVERSE = "reverse" LIT_MAGIC_STRING_SET_DATE_UL = "setDate" LIT_MAGIC_STRING_SET_TIME_UL = "setTime" diff --git a/tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-001.js b/tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-001.js index 0b3218aa6..73c6ae90b 100644 --- a/tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-001.js +++ b/tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-001.js @@ -13,4 +13,7 @@ * limitations under the License. */ -assert (Promise.prototype.length === 1); +Promise.resolve("abc").then(function(x) +{ + assert (x === "abc"); +}); diff --git a/tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-002.js b/tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-002.js index c1e7584f9..8445a4095 100644 --- a/tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-002.js +++ b/tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-002.js @@ -13,24 +13,13 @@ * limitations under the License. */ -var obj = {name:""}; +var a = new Promise(function(f) +{ + var o = {name: "abc"}; + f(o); +}) -var a = new Promise(function(f, r){ - obj.name = obj.name + "a"; - f(obj); +Promise.resolve(a).then(function(x) +{ + assert (x.name === "abc"); }); - -a.then(function(x) { - x.name = x.name + "b"; - return x; -}).then(null, function(x) { - x.name = x.name + "c"; // unreachable - return x; -}).then(function(x) { - x.name = x.name + "d"; - assert (obj.name === "aebd"); -}); - -obj.name = obj.name + "e"; - -assert (obj.name === "ae") diff --git a/tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-003.js b/tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-003.js index 6b4b90fb8..ea6570d1e 100644 --- a/tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-003.js +++ b/tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-003.js @@ -13,24 +13,10 @@ * limitations under the License. */ -var a = new Promise(function(f, r){ - r(0); +Promise.reject("abc").then(function(x) +{ + assert (false); // should not run here. +}, function(x) +{ + assert (x === "abc"); }); - -a -.then(function f1(x) { - return x + 1; // unreachable -}, function r1(x){ - return x + 10; -}) -.then(function f2(x) { - throw x + 100 -}) -.then(function f3(x) { - return x + 1000 //unreachable -}, function r3(x) { - return x + 10000 -}) -.then(function(x) { - assert (x === 10110); -}) diff --git a/tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-004.js b/tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-004.js index ce47a9aa6..b5e01d2cf 100644 --- a/tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-004.js +++ b/tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-004.js @@ -13,14 +13,37 @@ * limitations under the License. */ -var a = new Promise(function(f, r){ - f("a"); +var a = Promise.resolve('a'); +var b = Promise.reject('b'); + +Promise.race([a, b]).then(function(x) +{ + assert (x === 'a'); +}, function(x) +{ + assert (false); // should not run here. }); -var b = new Promise(function(f, r){ - f(a); -}) +Promise.race([b, a]).then(function(x) +{ + assert (false); // should not run here. +}, function(x) +{ + assert (x === 'b'); +}); -b.then(function(x) { - assert (x === "a"); -}) +Promise.race([ ,b, a]).then(function(x) +{ + assert (x === undefined); +}, function(x) +{ + assert (false); // should not run here. +}); + +Promise.race(a).then(function(x) +{ + assert (false); // should not run here. +}, function(x) +{ + assert(x.name === "TypeError"); +}); diff --git a/tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-005.js b/tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-005.js new file mode 100644 index 000000000..ac56e604a --- /dev/null +++ b/tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-005.js @@ -0,0 +1,52 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var a = Promise.resolve('a'); +var b = Promise.resolve('b'); +var c = Promise.reject('c'); + +Promise.all([a, b, 1]).then(function(x) +{ + assert (x[0] === 'a'); + assert (x[1] === 'b'); + assert (x[2] === 1); +}, function(x) +{ + assert (false); // should not run here. +}); + +Promise.all([a, b, c, 1]).then(function(x) +{ + assert (false); // should not run here. +}, function(x) +{ + assert (x === 'c'); +}); + +Promise.all([]).then(function(x) +{ + assert (x.length === 0); +}, function(x) +{ + assert (false); // should not run here. +}); + +Promise.all(a).then(function(x) +{ + assert (false); // should not run here. +}, function(x) +{ + assert(x.name === "TypeError"); +}); diff --git a/tests/jerry-test-suite/es2015/25/25.04/25.04.05/25.04.05-001.js b/tests/jerry-test-suite/es2015/25/25.04/25.04.05/25.04.05-001.js new file mode 100644 index 000000000..0b3218aa6 --- /dev/null +++ b/tests/jerry-test-suite/es2015/25/25.04/25.04.05/25.04.05-001.js @@ -0,0 +1,16 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +assert (Promise.prototype.length === 1); diff --git a/tests/jerry-test-suite/es2015/25/25.04/25.04.05/25.04.05-002.js b/tests/jerry-test-suite/es2015/25/25.04/25.04.05/25.04.05-002.js new file mode 100644 index 000000000..c1e7584f9 --- /dev/null +++ b/tests/jerry-test-suite/es2015/25/25.04/25.04.05/25.04.05-002.js @@ -0,0 +1,36 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var obj = {name:""}; + +var a = new Promise(function(f, r){ + obj.name = obj.name + "a"; + f(obj); +}); + +a.then(function(x) { + x.name = x.name + "b"; + return x; +}).then(null, function(x) { + x.name = x.name + "c"; // unreachable + return x; +}).then(function(x) { + x.name = x.name + "d"; + assert (obj.name === "aebd"); +}); + +obj.name = obj.name + "e"; + +assert (obj.name === "ae") diff --git a/tests/jerry-test-suite/es2015/25/25.04/25.04.05/25.04.05-003.js b/tests/jerry-test-suite/es2015/25/25.04/25.04.05/25.04.05-003.js new file mode 100644 index 000000000..6b4b90fb8 --- /dev/null +++ b/tests/jerry-test-suite/es2015/25/25.04/25.04.05/25.04.05-003.js @@ -0,0 +1,36 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var a = new Promise(function(f, r){ + r(0); +}); + +a +.then(function f1(x) { + return x + 1; // unreachable +}, function r1(x){ + return x + 10; +}) +.then(function f2(x) { + throw x + 100 +}) +.then(function f3(x) { + return x + 1000 //unreachable +}, function r3(x) { + return x + 10000 +}) +.then(function(x) { + assert (x === 10110); +}) diff --git a/tests/jerry-test-suite/es2015/25/25.04/25.04.05/25.04.05-004.js b/tests/jerry-test-suite/es2015/25/25.04/25.04.05/25.04.05-004.js new file mode 100644 index 000000000..ce47a9aa6 --- /dev/null +++ b/tests/jerry-test-suite/es2015/25/25.04/25.04.05/25.04.05-004.js @@ -0,0 +1,26 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var a = new Promise(function(f, r){ + f("a"); +}); + +var b = new Promise(function(f, r){ + f(a); +}) + +b.then(function(x) { + assert (x === "a"); +}) diff --git a/tests/jerry-test-suite/es2015/25/25.04/25.04.05/25.04.05-005.js b/tests/jerry-test-suite/es2015/25/25.04/25.04.05/25.04.05-005.js new file mode 100644 index 000000000..e0c5a2b70 --- /dev/null +++ b/tests/jerry-test-suite/es2015/25/25.04/25.04.05/25.04.05-005.js @@ -0,0 +1,22 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +Promise.reject("abc").catch(function(x) +{ + assert (x === "abc"); + return "def"; +}).then(function(x) { + assert (x === "def"); +}); diff --git a/tests/jerry/es2015/regression-test-issue-1763.js b/tests/jerry/es2015/regression-test-issue-1763.js new file mode 100644 index 000000000..cdbf96bf8 --- /dev/null +++ b/tests/jerry/es2015/regression-test-issue-1763.js @@ -0,0 +1,15 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +new Promise(Math.max.propertyIsEnumerable.toString).then()