2022-10-02 09:59:22 +00:00
/*
* Copyright ( c ) 2021 - 2022 , Linus Groh < linusg @ serenityos . org >
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# include <LibJS/Runtime/AbstractOperations.h>
# include <LibJS/Runtime/Error.h>
# include <LibJS/Runtime/NativeFunction.h>
# include <LibJS/Runtime/PromiseCapability.h>
namespace JS {
2024-11-14 15:01:23 +00:00
GC_DEFINE_ALLOCATOR ( PromiseCapability ) ;
2023-11-19 08:45:05 +00:00
2024-11-14 15:01:23 +00:00
GC : : Ref < PromiseCapability > PromiseCapability : : create ( VM & vm , GC : : Ref < Object > promise , GC : : Ref < FunctionObject > resolve , GC : : Ref < FunctionObject > reject )
2022-10-02 11:11:30 +00:00
{
2024-11-13 17:13:46 +00:00
return vm . heap ( ) . allocate < PromiseCapability > ( promise , resolve , reject ) ;
2022-10-02 11:11:30 +00:00
}
2024-11-14 15:01:23 +00:00
PromiseCapability : : PromiseCapability ( GC : : Ref < Object > promise , GC : : Ref < FunctionObject > resolve , GC : : Ref < FunctionObject > reject )
2022-10-02 11:11:30 +00:00
: m_promise ( promise )
, m_resolve ( resolve )
, m_reject ( reject )
{
}
void PromiseCapability : : visit_edges ( Cell : : Visitor & visitor )
{
2023-03-20 20:37:11 +00:00
Base : : visit_edges ( visitor ) ;
2022-10-02 11:11:30 +00:00
visitor . visit ( m_promise ) ;
visitor . visit ( m_resolve ) ;
visitor . visit ( m_reject ) ;
}
2023-06-28 21:38:45 +00:00
namespace {
struct ResolvingFunctions final : public Cell {
2024-11-14 15:01:23 +00:00
GC_CELL ( ResolvingFunctions , Cell ) ;
GC_DECLARE_ALLOCATOR ( ResolvingFunctions ) ;
2023-06-28 21:38:45 +00:00
Value resolve { js_undefined ( ) } ;
Value reject { js_undefined ( ) } ;
virtual void visit_edges ( Cell : : Visitor & visitor ) override
{
Base : : visit_edges ( visitor ) ;
visitor . visit ( resolve ) ;
visitor . visit ( reject ) ;
}
} ;
2024-11-14 15:01:23 +00:00
GC_DEFINE_ALLOCATOR ( ResolvingFunctions ) ;
2023-06-28 21:38:45 +00:00
}
2022-10-02 09:59:22 +00:00
// 27.2.1.5 NewPromiseCapability ( C ), https://tc39.es/ecma262/#sec-newpromisecapability
2024-11-14 15:01:23 +00:00
ThrowCompletionOr < GC : : Ref < PromiseCapability > > new_promise_capability ( VM & vm , Value constructor )
2022-10-02 09:59:22 +00:00
{
auto & realm = * vm . current_realm ( ) ;
// 1. If IsConstructor(C) is false, throw a TypeError exception.
if ( ! constructor . is_constructor ( ) )
2023-08-09 06:49:02 +00:00
return vm . throw_completion < TypeError > ( ErrorType : : NotAConstructor , constructor . to_string_without_side_effects ( ) ) ;
2022-10-02 09:59:22 +00:00
// 2. NOTE: C is assumed to be a constructor function that supports the parameter conventions of the Promise constructor (see 27.2.3.1).
2023-06-28 21:38:45 +00:00
// 3. Let resolvingFunctions be the Record { [[Resolve]]: undefined, [[Reject]]: undefined }.
2024-11-13 16:50:17 +00:00
auto resolving_functions = realm . create < ResolvingFunctions > ( ) ;
2022-10-02 09:59:22 +00:00
2023-06-28 21:38:45 +00:00
// 4. Let executorClosure be a new Abstract Closure with parameters (resolve, reject) that captures resolvingFunctions and performs the following steps when called:
auto executor_closure = [ resolving_functions ] ( auto & vm ) - > ThrowCompletionOr < Value > {
2022-10-02 09:59:22 +00:00
auto resolve = vm . argument ( 0 ) ;
auto reject = vm . argument ( 1 ) ;
// No idea what other engines say here.
// a. If promiseCapability.[[Resolve]] is not undefined, throw a TypeError exception.
2023-06-28 21:38:45 +00:00
if ( ! resolving_functions - > resolve . is_undefined ( ) )
2022-10-02 09:59:22 +00:00
return vm . template throw_completion < TypeError > ( ErrorType : : GetCapabilitiesExecutorCalledMultipleTimes ) ;
// b. If promiseCapability.[[Reject]] is not undefined, throw a TypeError exception.
2023-06-28 21:38:45 +00:00
if ( ! resolving_functions - > reject . is_undefined ( ) )
2022-10-02 09:59:22 +00:00
return vm . template throw_completion < TypeError > ( ErrorType : : GetCapabilitiesExecutorCalledMultipleTimes ) ;
// c. Set promiseCapability.[[Resolve]] to resolve.
2023-06-28 21:38:45 +00:00
resolving_functions - > resolve = resolve ;
2022-10-02 09:59:22 +00:00
// d. Set promiseCapability.[[Reject]] to reject.
2023-06-28 21:38:45 +00:00
resolving_functions - > reject = reject ;
2022-10-02 09:59:22 +00:00
// e. Return undefined.
return js_undefined ( ) ;
} ;
// 5. Let executor be CreateBuiltinFunction(executorClosure, 2, "", « »).
2022-12-13 20:49:50 +00:00
auto executor = NativeFunction : : create ( realm , move ( executor_closure ) , 2 , " " ) ;
2022-10-02 09:59:22 +00:00
// 6. Let promise be ? Construct(C, « executor »).
2022-12-13 20:49:50 +00:00
auto promise = TRY ( construct ( vm , constructor . as_function ( ) , executor ) ) ;
2022-10-02 09:59:22 +00:00
2023-06-28 21:38:45 +00:00
// 7. If IsCallable(resolvingFunctions.[[Resolve]]) is false, throw a TypeError exception.
if ( ! resolving_functions - > resolve . is_function ( ) )
2022-10-02 17:44:30 +00:00
return vm . throw_completion < TypeError > ( ErrorType : : NotAFunction , " Promise capability resolve value " ) ;
2022-10-02 09:59:22 +00:00
2023-06-28 21:38:45 +00:00
// 8. If IsCallable(resolvingFunctions.[[Reject]]) is false, throw a TypeError exception.
2023-06-29 06:28:15 +00:00
if ( ! resolving_functions - > reject . is_function ( ) )
2022-10-02 17:44:30 +00:00
return vm . throw_completion < TypeError > ( ErrorType : : NotAFunction , " Promise capability reject value " ) ;
2022-10-02 09:59:22 +00:00
2023-06-28 21:38:45 +00:00
// 9. Return the PromiseCapability Record { [[Promise]]: promise, [[Resolve]]: resolvingFunctions.[[Resolve]], [[Reject]]: resolvingFunctions.[[Reject]] }.
return PromiseCapability : : create ( vm , promise , resolving_functions - > resolve . as_function ( ) , resolving_functions - > reject . as_function ( ) ) ;
2022-10-02 09:59:22 +00:00
}
}