Implement CreateAsyncFromSyncIterator (#4802)
JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik robert.fancsik@h-lab.eu
This commit is contained in:
@@ -202,16 +202,49 @@ ecma_op_get_iterator (ecma_value_t value, /**< value to get iterator from */
|
||||
return method;
|
||||
}
|
||||
}
|
||||
/* 3.a */
|
||||
else if (method == ECMA_VALUE_ASYNC_ITERATOR)
|
||||
{
|
||||
/* TODO: CreateAsyncFromSyncIterator should be supported. */
|
||||
use_default_method = true;
|
||||
|
||||
/* 3.a.i */
|
||||
method = ecma_op_get_method_by_symbol_id (value, LIT_GLOBAL_SYMBOL_ASYNC_ITERATOR);
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (method))
|
||||
{
|
||||
return method;
|
||||
}
|
||||
|
||||
/* 3.a.ii */
|
||||
|
||||
if (ecma_is_value_undefined (method))
|
||||
{
|
||||
method = ecma_op_get_method_by_symbol_id (value, LIT_GLOBAL_SYMBOL_ITERATOR);
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (method))
|
||||
{
|
||||
return method;
|
||||
}
|
||||
|
||||
ecma_value_t sync_next_method;
|
||||
ecma_value_t sync_iterator = ecma_op_get_iterator (value, method, &sync_next_method);
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (sync_iterator))
|
||||
{
|
||||
ecma_free_value (method);
|
||||
return sync_iterator;
|
||||
}
|
||||
|
||||
ecma_value_t async_iterator = ecma_op_create_async_from_sync_iterator (sync_iterator,
|
||||
sync_next_method,
|
||||
next_method_p);
|
||||
|
||||
ecma_free_value (method);
|
||||
ecma_free_value (sync_iterator);
|
||||
ecma_free_value (sync_next_method);
|
||||
|
||||
return async_iterator;
|
||||
}
|
||||
}
|
||||
|
||||
/* 3. */
|
||||
@@ -396,6 +429,35 @@ ecma_op_iterator_throw (ecma_value_t iterator, /**< iterator value */
|
||||
return result;
|
||||
} /* ecma_op_iterator_throw */
|
||||
|
||||
/**
|
||||
* IteratorComplete operation
|
||||
*
|
||||
* See also: ECMA-262 v10, 7.4.3
|
||||
*
|
||||
* @return true/false - whether the iteration ended
|
||||
*/
|
||||
ecma_value_t
|
||||
ecma_op_iterator_complete (ecma_value_t iter_result) /**< iterator value */
|
||||
{
|
||||
/* 1. */
|
||||
JERRY_ASSERT (ecma_is_value_object (iter_result));
|
||||
|
||||
/* 2. */
|
||||
ecma_object_t *obj_p = ecma_get_object_from_value (iter_result);
|
||||
|
||||
ecma_value_t done = ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_DONE);
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (done))
|
||||
{
|
||||
return done;
|
||||
}
|
||||
|
||||
ecma_value_t res = ecma_make_boolean_value (ecma_op_to_boolean (done));
|
||||
ecma_free_value (done);
|
||||
|
||||
return res;
|
||||
} /* ecma_op_iterator_complete */
|
||||
|
||||
/**
|
||||
* IteratorValue operation
|
||||
*
|
||||
@@ -623,6 +685,66 @@ ecma_op_iterator_do (ecma_iterator_command_type_t command, /**< command to be ex
|
||||
return result;
|
||||
} /* ecma_op_iterator_do */
|
||||
|
||||
/**
|
||||
* CreateAsyncFromSyncIterator operation
|
||||
*
|
||||
* See also: ECMA-262 v10, 25.1.4.1
|
||||
*
|
||||
* Note:
|
||||
* Returned value must be freed with ecma_free_value.
|
||||
*
|
||||
* @return async from sync iterator object
|
||||
*/
|
||||
ecma_value_t
|
||||
ecma_op_create_async_from_sync_iterator (ecma_value_t sync_iterator, /**< sync iterator */
|
||||
ecma_value_t sync_next_method, /**< sync iterator next method */
|
||||
ecma_value_t *async_next_method_p) /**< [out] async next method */
|
||||
{
|
||||
JERRY_ASSERT (ecma_is_value_object (sync_iterator));
|
||||
JERRY_ASSERT (ecma_is_value_object (sync_next_method) || ecma_is_value_undefined (sync_next_method));
|
||||
|
||||
/* 1. */
|
||||
ecma_object_t *obj_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_ASYNC_FROM_SYNC_ITERATOR_PROTOTYPE),
|
||||
sizeof (ecma_async_from_sync_iterator_object_t),
|
||||
ECMA_OBJECT_TYPE_CLASS);
|
||||
|
||||
ecma_async_from_sync_iterator_object_t *ext_obj_p = (ecma_async_from_sync_iterator_object_t *) obj_p;
|
||||
|
||||
/* 2. */
|
||||
ext_obj_p->sync_next_method = sync_next_method;
|
||||
ext_obj_p->header.u.cls.u3.sync_iterator = sync_iterator;
|
||||
ext_obj_p->header.u.cls.type = ECMA_OBJECT_CLASS_ASYNC_FROM_SYNC_ITERATOR;
|
||||
|
||||
/* 3. */
|
||||
*async_next_method_p = ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_NEXT);
|
||||
JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (*async_next_method_p));
|
||||
|
||||
/* 4. */
|
||||
return ecma_make_object_value (obj_p);
|
||||
} /* ecma_op_create_async_from_sync_iterator */
|
||||
|
||||
/**
|
||||
* Async-from-Sync Iterator Value Unwrap Functions
|
||||
*
|
||||
* See also: ES11 25.1.4.2.4
|
||||
*
|
||||
* @return iterator result object
|
||||
*/
|
||||
ecma_value_t
|
||||
ecma_async_from_sync_iterator_unwrap_cb (ecma_object_t *function_obj_p, /**< function object */
|
||||
const ecma_value_t args_p[], /**< argument list */
|
||||
const uint32_t args_count) /**< argument number */
|
||||
{
|
||||
ecma_extended_object_t *unwrap_p = (ecma_extended_object_t *) function_obj_p;
|
||||
|
||||
/* 2. */
|
||||
ecma_value_t arg = args_count > 0 ? args_p[0] : ECMA_VALUE_UNDEFINED;
|
||||
ecma_value_t done = ecma_make_boolean_value (unwrap_p->u.built_in.u2.routine_flags
|
||||
>> ECMA_NATIVE_HANDLER_COMMON_FLAGS_SHIFT);
|
||||
|
||||
return ecma_create_iter_result_object (arg, done);
|
||||
} /* ecma_async_from_sync_iterator_unwrap_cb */
|
||||
|
||||
#endif /* JERRY_ESNEXT */
|
||||
|
||||
/**
|
||||
|
||||
@@ -58,6 +58,9 @@ ecma_create_array_from_iter_element (ecma_value_t value, ecma_value_t index_valu
|
||||
ecma_value_t
|
||||
ecma_op_get_iterator (ecma_value_t value, ecma_value_t method, ecma_value_t *next_method_p);
|
||||
|
||||
ecma_value_t
|
||||
ecma_op_iterator_complete (ecma_value_t iter_result);
|
||||
|
||||
ecma_value_t
|
||||
ecma_op_iterator_value (ecma_value_t iter_result);
|
||||
|
||||
@@ -74,6 +77,15 @@ ecma_value_t
|
||||
ecma_op_iterator_do (ecma_iterator_command_type_t command, ecma_value_t iterator,
|
||||
ecma_value_t next_method, ecma_value_t value, bool *done_p);
|
||||
|
||||
ecma_value_t
|
||||
ecma_op_create_async_from_sync_iterator (ecma_value_t sync_iterator, ecma_value_t sync_next_method,
|
||||
ecma_value_t *async_next_method_p);
|
||||
|
||||
ecma_value_t
|
||||
ecma_async_from_sync_iterator_unwrap_cb (ecma_object_t *function_obj_p,
|
||||
const ecma_value_t args_p[],
|
||||
const uint32_t args_count);
|
||||
|
||||
#endif /* JERRY_ESNEXT */
|
||||
|
||||
/**
|
||||
|
||||
@@ -2937,6 +2937,7 @@ static const uint16_t ecma_class_object_magic_string_id[] =
|
||||
#if JERRY_ESNEXT
|
||||
LIT_MAGIC_STRING_PROMISE_UL, /**< magic string id of ECMA_OBJECT_CLASS_PROMISE */
|
||||
LIT_MAGIC_STRING_OBJECT_UL, /**< magic string id of ECMA_OBJECT_CLASS_PROMISE_CAPABILITY */
|
||||
LIT_MAGIC_STRING_OBJECT_UL, /**< magic string id of ECMA_OBJECT_CLASS_ASYNC_FROM_SYNC_ITERATOR */
|
||||
#endif /* JERRY_ESNEXT */
|
||||
#if JERRY_BUILTIN_DATAVIEW
|
||||
LIT_MAGIC_STRING_DATAVIEW_UL, /**< magic string id of ECMA_OBJECT_CLASS_DATAVIEW */
|
||||
|
||||
@@ -607,7 +607,7 @@ ecma_promise_all_or_all_settled_handler_cb (ecma_object_t *function_obj_p, /**<
|
||||
ecma_promise_all_executor_t *executor_p = (ecma_promise_all_executor_t *) function_obj_p;
|
||||
uint8_t promise_type = executor_p->header.u.built_in.u2.routine_flags;
|
||||
|
||||
promise_type = (uint8_t) (promise_type >> ECMA_NATIVE_HANDLER_FLAGS_PROMISE_HELPER_SHIFT);
|
||||
promise_type = (uint8_t) (promise_type >> ECMA_NATIVE_HANDLER_COMMON_FLAGS_SHIFT);
|
||||
|
||||
/* 1 - 2. */
|
||||
if (executor_p->index == 0)
|
||||
@@ -894,103 +894,6 @@ ecma_promise_reject_or_resolve (ecma_value_t this_arg, /**< "this" argument */
|
||||
return promise;
|
||||
} /* ecma_promise_reject_or_resolve */
|
||||
|
||||
/**
|
||||
* It performs the "then" operation on promiFulfilled
|
||||
* and onRejected as its settlement actions.
|
||||
*
|
||||
* See also: 25.4.5.3.1
|
||||
*
|
||||
* @return ecma value of the new promise object
|
||||
* Returned value must be freed with ecma_free_value
|
||||
*/
|
||||
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_object_t *result_capability_obj_p) /**< promise capability */
|
||||
{
|
||||
JERRY_ASSERT (ecma_object_class_is (result_capability_obj_p, ECMA_OBJECT_CLASS_PROMISE_CAPABILITY));
|
||||
|
||||
ecma_promise_capabality_t *capability_p = (ecma_promise_capabality_t *) result_capability_obj_p;
|
||||
|
||||
/* 3. boolean true indicates "indentity" */
|
||||
if (!ecma_op_is_callable (on_fulfilled))
|
||||
{
|
||||
on_fulfilled = ECMA_VALUE_TRUE;
|
||||
}
|
||||
|
||||
/* 4. boolean false indicates "thrower" */
|
||||
if (!ecma_op_is_callable (on_rejected))
|
||||
{
|
||||
on_rejected = ECMA_VALUE_FALSE;
|
||||
}
|
||||
|
||||
ecma_object_t *promise_obj_p = ecma_get_object_from_value (promise);
|
||||
ecma_promise_object_t *promise_p = (ecma_promise_object_t *) promise_obj_p;
|
||||
|
||||
uint16_t flags = ecma_promise_get_flags (promise_obj_p);
|
||||
|
||||
if (flags & ECMA_PROMISE_IS_PENDING)
|
||||
{
|
||||
/* 7. */
|
||||
/* [ capability, (on_fulfilled), (on_rejected) ] */
|
||||
ecma_value_t reaction_values[3];
|
||||
ecma_value_t *reactions_p = reaction_values + 1;
|
||||
|
||||
uint8_t tag = 0;
|
||||
|
||||
if (on_fulfilled != ECMA_VALUE_TRUE)
|
||||
{
|
||||
tag |= JMEM_FIRST_TAG_BIT_MASK;
|
||||
*reactions_p++ = on_fulfilled;
|
||||
}
|
||||
|
||||
if (on_rejected != ECMA_VALUE_FALSE)
|
||||
{
|
||||
tag |= JMEM_SECOND_TAG_BIT_MASK;
|
||||
*reactions_p++ = on_rejected;
|
||||
}
|
||||
|
||||
ECMA_SET_NON_NULL_POINTER_TAG (reaction_values[0], result_capability_obj_p, tag);
|
||||
|
||||
uint32_t value_count = (uint32_t) (reactions_p - reaction_values);
|
||||
ecma_collection_append (promise_p->reactions, reaction_values, value_count);
|
||||
}
|
||||
else if (flags & ECMA_PROMISE_IS_FULFILLED)
|
||||
{
|
||||
/* 8. */
|
||||
ecma_value_t value = ecma_promise_get_result (promise_obj_p);
|
||||
ecma_enqueue_promise_reaction_job (ecma_make_object_value (result_capability_obj_p), on_fulfilled, value);
|
||||
ecma_free_value (value);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 9. */
|
||||
ecma_value_t reason = ecma_promise_get_result (promise_obj_p);
|
||||
ecma_enqueue_promise_reaction_job (ecma_make_object_value (result_capability_obj_p), on_rejected, reason);
|
||||
ecma_free_value (reason);
|
||||
|
||||
#if JERRY_PROMISE_CALLBACK
|
||||
if (ecma_promise_get_flags (promise_obj_p) & ECMA_PROMISE_UNHANDLED_REJECT)
|
||||
{
|
||||
promise_p->header.u.cls.u1.promise_flags &= (uint8_t) ~ECMA_PROMISE_UNHANDLED_REJECT;
|
||||
|
||||
if (JERRY_UNLIKELY (JERRY_CONTEXT (promise_callback_filters) & JERRY_PROMISE_EVENT_FILTER_ERROR))
|
||||
{
|
||||
JERRY_ASSERT (JERRY_CONTEXT (promise_callback) != NULL);
|
||||
JERRY_CONTEXT (promise_callback) (JERRY_PROMISE_EVENT_CATCH_HANDLER_ADDED,
|
||||
promise,
|
||||
ECMA_VALUE_UNDEFINED,
|
||||
JERRY_CONTEXT (promise_callback_user_p));
|
||||
}
|
||||
}
|
||||
#endif /* JERRY_PROMISE_CALLBACK */
|
||||
}
|
||||
|
||||
/* 10. */
|
||||
return ecma_copy_value (capability_p->header.u.cls.u3.promise);
|
||||
} /* ecma_promise_do_then */
|
||||
|
||||
/**
|
||||
* The common function for ecma_builtin_promise_prototype_then
|
||||
* and ecma_builtin_promise_prototype_catch.
|
||||
@@ -1029,7 +932,7 @@ ecma_promise_then (ecma_value_t promise, /**< the promise which call 'then' */
|
||||
return ECMA_VALUE_ERROR;
|
||||
}
|
||||
|
||||
ecma_value_t ret = ecma_promise_do_then (promise, on_fulfilled, on_rejected, result_capability_obj_p);
|
||||
ecma_value_t ret = ecma_promise_perform_then (promise, on_fulfilled, on_rejected, result_capability_obj_p);
|
||||
ecma_deref_object (result_capability_obj_p);
|
||||
|
||||
return ret;
|
||||
@@ -1326,6 +1229,144 @@ ecma_promise_async_await (ecma_extended_object_t *async_generator_object_p, /**<
|
||||
return ECMA_VALUE_UNDEFINED;
|
||||
} /* ecma_promise_async_await */
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
ecma_value_t
|
||||
ecma_op_if_abrupt_reject_promise (ecma_value_t *value_p, /**< [in - out] completion value */
|
||||
ecma_object_t *capability_obj_p) /**< capability */
|
||||
{
|
||||
JERRY_ASSERT (ecma_object_class_is (capability_obj_p, ECMA_OBJECT_CLASS_PROMISE_CAPABILITY));
|
||||
|
||||
if (!ECMA_IS_VALUE_ERROR (*value_p))
|
||||
{
|
||||
return ECMA_VALUE_EMPTY;
|
||||
}
|
||||
|
||||
ecma_value_t reason = jcontext_take_exception ();
|
||||
|
||||
ecma_promise_capabality_t *capability_p = (ecma_promise_capabality_t *) capability_obj_p;
|
||||
ecma_value_t call_ret = ecma_op_function_call (ecma_get_object_from_value (capability_p->reject),
|
||||
ECMA_VALUE_UNDEFINED,
|
||||
&reason,
|
||||
1);
|
||||
ecma_free_value (reason);
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (call_ret))
|
||||
{
|
||||
*value_p = call_ret;
|
||||
return call_ret;
|
||||
}
|
||||
|
||||
ecma_free_value (call_ret);
|
||||
*value_p = ecma_copy_value (capability_p->header.u.cls.u3.promise);
|
||||
|
||||
return ECMA_VALUE_EMPTY;
|
||||
} /* ecma_op_if_abrupt_reject_promise */
|
||||
|
||||
/**
|
||||
* It performs the "then" operation on promiFulfilled
|
||||
* and onRejected as its settlement actions.
|
||||
*
|
||||
* See also: 25.4.5.3.1
|
||||
*
|
||||
* @return ecma value of the new promise object
|
||||
* Returned value must be freed with ecma_free_value
|
||||
*/
|
||||
ecma_value_t
|
||||
ecma_promise_perform_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 *result_capability_obj_p) /**< promise capability */
|
||||
{
|
||||
JERRY_ASSERT (ecma_object_class_is (result_capability_obj_p, ECMA_OBJECT_CLASS_PROMISE_CAPABILITY));
|
||||
|
||||
ecma_promise_capabality_t *capability_p = (ecma_promise_capabality_t *) result_capability_obj_p;
|
||||
|
||||
/* 3. boolean true indicates "indentity" */
|
||||
if (!ecma_op_is_callable (on_fulfilled))
|
||||
{
|
||||
on_fulfilled = ECMA_VALUE_TRUE;
|
||||
}
|
||||
|
||||
/* 4. boolean false indicates "thrower" */
|
||||
if (!ecma_op_is_callable (on_rejected))
|
||||
{
|
||||
on_rejected = ECMA_VALUE_FALSE;
|
||||
}
|
||||
|
||||
ecma_object_t *promise_obj_p = ecma_get_object_from_value (promise);
|
||||
ecma_promise_object_t *promise_p = (ecma_promise_object_t *) promise_obj_p;
|
||||
|
||||
uint16_t flags = ecma_promise_get_flags (promise_obj_p);
|
||||
|
||||
if (flags & ECMA_PROMISE_IS_PENDING)
|
||||
{
|
||||
/* 7. */
|
||||
/* [ capability, (on_fulfilled), (on_rejected) ] */
|
||||
ecma_value_t reaction_values[3];
|
||||
ecma_value_t *reactions_p = reaction_values + 1;
|
||||
|
||||
uint8_t tag = 0;
|
||||
|
||||
if (on_fulfilled != ECMA_VALUE_TRUE)
|
||||
{
|
||||
tag |= JMEM_FIRST_TAG_BIT_MASK;
|
||||
*reactions_p++ = on_fulfilled;
|
||||
}
|
||||
|
||||
if (on_rejected != ECMA_VALUE_FALSE)
|
||||
{
|
||||
tag |= JMEM_SECOND_TAG_BIT_MASK;
|
||||
*reactions_p++ = on_rejected;
|
||||
}
|
||||
|
||||
ECMA_SET_NON_NULL_POINTER_TAG (reaction_values[0], result_capability_obj_p, tag);
|
||||
|
||||
uint32_t value_count = (uint32_t) (reactions_p - reaction_values);
|
||||
ecma_collection_append (promise_p->reactions, reaction_values, value_count);
|
||||
}
|
||||
else if (flags & ECMA_PROMISE_IS_FULFILLED)
|
||||
{
|
||||
/* 8. */
|
||||
ecma_value_t value = ecma_promise_get_result (promise_obj_p);
|
||||
ecma_enqueue_promise_reaction_job (ecma_make_object_value (result_capability_obj_p), on_fulfilled, value);
|
||||
ecma_free_value (value);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 9. */
|
||||
ecma_value_t reason = ecma_promise_get_result (promise_obj_p);
|
||||
ecma_enqueue_promise_reaction_job (ecma_make_object_value (result_capability_obj_p), on_rejected, reason);
|
||||
ecma_free_value (reason);
|
||||
|
||||
#if JERRY_PROMISE_CALLBACK
|
||||
if (ecma_promise_get_flags (promise_obj_p) & ECMA_PROMISE_UNHANDLED_REJECT)
|
||||
{
|
||||
promise_p->header.u.cls.u1.promise_flags &= (uint8_t) ~ECMA_PROMISE_UNHANDLED_REJECT;
|
||||
|
||||
if (JERRY_UNLIKELY (JERRY_CONTEXT (promise_callback_filters) & JERRY_PROMISE_EVENT_FILTER_ERROR))
|
||||
{
|
||||
JERRY_ASSERT (JERRY_CONTEXT (promise_callback) != NULL);
|
||||
JERRY_CONTEXT (promise_callback) (JERRY_PROMISE_EVENT_CATCH_HANDLER_ADDED,
|
||||
promise,
|
||||
ECMA_VALUE_UNDEFINED,
|
||||
JERRY_CONTEXT (promise_callback_user_p));
|
||||
}
|
||||
}
|
||||
#endif /* JERRY_PROMISE_CALLBACK */
|
||||
}
|
||||
|
||||
/* 10. */
|
||||
return ecma_copy_value (capability_p->header.u.cls.u3.promise);
|
||||
} /* ecma_promise_perform_then */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
|
||||
@@ -129,9 +129,15 @@ ecma_value_t ecma_promise_finally (ecma_value_t promise, ecma_value_t on_finally
|
||||
void ecma_promise_async_then (ecma_value_t promise, ecma_value_t executable_object);
|
||||
ecma_value_t ecma_promise_async_await (ecma_extended_object_t *async_generator_object_p, ecma_value_t value);
|
||||
ecma_value_t ecma_promise_run_executor (ecma_object_t *promise_p, ecma_value_t executor, ecma_value_t this_value);
|
||||
ecma_value_t ecma_op_if_abrupt_reject_promise (ecma_value_t *value_p, ecma_object_t *capability_obj_p);
|
||||
|
||||
uint32_t ecma_promise_remaining_inc_or_dec (ecma_value_t remaining, bool is_inc);
|
||||
|
||||
ecma_value_t ecma_promise_perform_then (ecma_value_t promise,
|
||||
ecma_value_t on_fulfilled,
|
||||
ecma_value_t on_rejected,
|
||||
ecma_object_t *result_capability_obj_p);
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
|
||||
Reference in New Issue
Block a user