/src/serenity/Userland/Libraries/LibJS/Runtime/PromiseCapability.h
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2021-2022, Linus Groh <linusg@serenityos.org> |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #pragma once |
8 | | |
9 | | #include <AK/Forward.h> |
10 | | #include <LibJS/Forward.h> |
11 | | #include <LibJS/Runtime/AbstractOperations.h> |
12 | | |
13 | | namespace JS { |
14 | | |
15 | | // 27.2.1.1 PromiseCapability Records, https://tc39.es/ecma262/#sec-promisecapability-records |
16 | | class PromiseCapability final : public Cell { |
17 | | JS_CELL(PromiseCapability, Cell); |
18 | | JS_DECLARE_ALLOCATOR(PromiseCapability); |
19 | | |
20 | | public: |
21 | | static NonnullGCPtr<PromiseCapability> create(VM& vm, NonnullGCPtr<Object> promise, NonnullGCPtr<FunctionObject> resolve, NonnullGCPtr<FunctionObject> reject); |
22 | | |
23 | | virtual ~PromiseCapability() = default; |
24 | | |
25 | 0 | [[nodiscard]] NonnullGCPtr<Object> promise() const { return m_promise; } |
26 | | |
27 | 0 | [[nodiscard]] NonnullGCPtr<FunctionObject> resolve() const { return m_resolve; } |
28 | | |
29 | 0 | [[nodiscard]] NonnullGCPtr<FunctionObject> reject() const { return m_reject; } |
30 | | |
31 | | private: |
32 | | PromiseCapability(NonnullGCPtr<Object>, NonnullGCPtr<FunctionObject>, NonnullGCPtr<FunctionObject>); |
33 | | |
34 | | virtual void visit_edges(Visitor&) override; |
35 | | |
36 | | NonnullGCPtr<Object> m_promise; |
37 | | NonnullGCPtr<FunctionObject> m_resolve; |
38 | | NonnullGCPtr<FunctionObject> m_reject; |
39 | | }; |
40 | | |
41 | | // 27.2.1.1.1 IfAbruptRejectPromise ( value, capability ), https://tc39.es/ecma262/#sec-ifabruptrejectpromise |
42 | | #define __TRY_OR_REJECT(vm, capability, expression, CALL_CHECK) \ |
43 | 0 | ({ \ |
44 | 0 | auto&& _temporary_try_or_reject_result = (expression); \ |
45 | 0 | /* 1. If value is an abrupt completion, then */ \ |
46 | 0 | if (_temporary_try_or_reject_result.is_error()) { \ |
47 | 0 | /* a. Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »). */ \ |
48 | 0 | CALL_CHECK(JS::call(vm, *(capability)->reject(), js_undefined(), *_temporary_try_or_reject_result.release_error().value())); \ |
49 | 0 | \ |
50 | 0 | /* b. Return capability.[[Promise]]. */ \ |
51 | 0 | return (capability)->promise(); \ |
52 | 0 | } \ |
53 | 0 | \ |
54 | 0 | static_assert(!::AK::Detail::IsLvalueReference<decltype(_temporary_try_or_reject_result.release_value())>, \ |
55 | 0 | "Do not return a reference from a fallible expression"); \ |
56 | 0 | \ |
57 | 0 | /* 2. Else if value is a Completion Record, set value to value.[[Value]]. */ \ |
58 | 0 | _temporary_try_or_reject_result.release_value(); \ |
59 | 0 | }) |
60 | | |
61 | | #define TRY_OR_REJECT(vm, capability, expression) \ |
62 | 0 | __TRY_OR_REJECT(vm, capability, expression, TRY) |
63 | | |
64 | | #define TRY_OR_MUST_REJECT(vm, capability, expression) \ |
65 | 0 | __TRY_OR_REJECT(vm, capability, expression, MUST) |
66 | | |
67 | | // 27.2.1.1.1 IfAbruptRejectPromise ( value, capability ), https://tc39.es/ecma262/#sec-ifabruptrejectpromise |
68 | | #define TRY_OR_REJECT_WITH_VALUE(vm, capability, expression) \ |
69 | 0 | ({ \ |
70 | 0 | auto&& _temporary_try_or_reject_result = (expression); \ |
71 | 0 | /* 1. If value is an abrupt completion, then */ \ |
72 | 0 | if (_temporary_try_or_reject_result.is_error()) { \ |
73 | 0 | /* a. Perform ? Call(capability.[[Reject]], undefined, « value.[[Value]] »). */ \ |
74 | 0 | TRY(JS::call(vm, *(capability)->reject(), js_undefined(), *_temporary_try_or_reject_result.release_error().value())); \ |
75 | 0 | \ |
76 | 0 | /* b. Return capability.[[Promise]]. */ \ |
77 | 0 | return Value { (capability)->promise() }; \ |
78 | 0 | } \ |
79 | 0 | \ |
80 | 0 | static_assert(!::AK::Detail::IsLvalueReference<decltype(_temporary_try_or_reject_result.release_value())>, \ |
81 | 0 | "Do not return a reference from a fallible expression"); \ |
82 | 0 | \ |
83 | 0 | /* 2. Else if value is a Completion Record, set value to value.[[Value]]. */ \ |
84 | 0 | _temporary_try_or_reject_result.release_value(); \ |
85 | 0 | }) |
86 | | |
87 | | // 27.2.1.5 NewPromiseCapability ( C ), https://tc39.es/ecma262/#sec-newpromisecapability |
88 | | ThrowCompletionOr<NonnullGCPtr<PromiseCapability>> new_promise_capability(VM& vm, Value constructor); |
89 | | |
90 | | } |