Completion.h 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. /*
  2. * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2021-2022, Linus Groh <linusg@serenityos.org>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #pragma once
  8. #include <AK/FlyString.h>
  9. #include <AK/Optional.h>
  10. #include <AK/Try.h>
  11. #include <AK/Variant.h>
  12. #include <LibJS/Runtime/Value.h>
  13. namespace JS {
  14. // 6.2.3 The Completion Record Specification Type, https://tc39.es/ecma262/#sec-completion-record-specification-type
  15. class [[nodiscard]] Completion {
  16. public:
  17. enum class Type {
  18. Empty,
  19. Normal,
  20. Break,
  21. Continue,
  22. Return,
  23. Throw,
  24. };
  25. ALWAYS_INLINE Completion(Type type, Optional<Value> value, Optional<FlyString> target)
  26. : m_type(type)
  27. , m_value(move(value))
  28. , m_target(move(target))
  29. {
  30. VERIFY(type != Type::Empty);
  31. if (m_value.has_value())
  32. VERIFY(!m_value->is_empty());
  33. }
  34. Completion(ThrowCompletionOr<Value> const&);
  35. // 5.2.3.1 Implicit Completion Values, https://tc39.es/ecma262/#sec-implicit-completion-values
  36. // Not `explicit` on purpose.
  37. ALWAYS_INLINE Completion(Value value)
  38. : Completion(Type::Normal, value, {})
  39. {
  40. }
  41. ALWAYS_INLINE Completion(Optional<Value> value)
  42. : Completion(Type::Normal, move(value), {})
  43. {
  44. }
  45. ALWAYS_INLINE Completion()
  46. : Completion(js_undefined())
  47. {
  48. }
  49. Completion(Completion const&) = default;
  50. Completion& operator=(Completion const&) = default;
  51. Completion(Completion&&) = default;
  52. Completion& operator=(Completion&&) = default;
  53. [[nodiscard]] Type type() const
  54. {
  55. VERIFY(m_type != Type::Empty);
  56. return m_type;
  57. }
  58. [[nodiscard]] Optional<Value>& value() { return m_value; }
  59. [[nodiscard]] Optional<Value> const& value() const { return m_value; }
  60. [[nodiscard]] Optional<FlyString>& target() { return m_target; }
  61. [[nodiscard]] Optional<FlyString> const& target() const { return m_target; }
  62. // "abrupt completion refers to any completion with a [[Type]] value other than normal"
  63. [[nodiscard]] bool is_abrupt() const { return m_type != Type::Normal; }
  64. // These are for compatibility with the TRY() macro in AK.
  65. [[nodiscard]] bool is_error() const { return m_type == Type::Throw; }
  66. [[nodiscard]] Optional<Value> release_value() { return move(m_value); }
  67. Completion release_error()
  68. {
  69. VERIFY(is_error());
  70. VERIFY(m_value.has_value());
  71. return { m_type, release_value(), move(m_target) };
  72. }
  73. // 6.2.3.4 UpdateEmpty ( completionRecord, value ), https://tc39.es/ecma262/#sec-updateempty
  74. Completion update_empty(Optional<Value> value) const
  75. {
  76. // 1. Assert: If completionRecord.[[Type]] is either return or throw, then completionRecord.[[Value]] is not empty.
  77. if (m_type == Type::Return || m_type == Type::Throw)
  78. VERIFY(m_value.has_value());
  79. // 2. If completionRecord.[[Value]] is not empty, return ? completionRecord.
  80. if (m_value.has_value())
  81. return *this;
  82. // 3. Return Completion Record { [[Type]]: completionRecord.[[Type]], [[Value]]: value, [[Target]]: completionRecord.[[Target]] }.
  83. return { m_type, move(value), m_target };
  84. }
  85. private:
  86. class EmptyTag {
  87. };
  88. friend AK::Optional<Completion>;
  89. Completion(EmptyTag)
  90. : m_type(Type::Empty)
  91. {
  92. }
  93. bool is_empty() const
  94. {
  95. return m_type == Type::Empty;
  96. }
  97. Type m_type { Type::Normal }; // [[Type]]
  98. Optional<Value> m_value; // [[Value]]
  99. Optional<FlyString> m_target; // [[Target]]
  100. };
  101. }
  102. namespace AK {
  103. template<>
  104. class Optional<JS::Completion> {
  105. template<typename U>
  106. friend class Optional;
  107. public:
  108. using ValueType = JS::Completion;
  109. Optional()
  110. : m_value(JS::Completion(JS::Completion::EmptyTag {}))
  111. {
  112. }
  113. Optional(Optional<JS::Completion> const& other)
  114. {
  115. if (other.has_value())
  116. m_value = other.m_value;
  117. }
  118. Optional(Optional&& other)
  119. : m_value(other.m_value)
  120. {
  121. }
  122. template<typename U = JS::Completion>
  123. explicit(!IsConvertible<U&&, JS::Completion>) Optional(U&& value)
  124. requires(!IsSame<RemoveCVReference<U>, Optional<JS::Completion>> && IsConstructible<JS::Completion, U &&>)
  125. : m_value(forward<U>(value))
  126. {
  127. }
  128. Optional& operator=(Optional const& other)
  129. {
  130. if (this != &other) {
  131. clear();
  132. m_value = other.m_value;
  133. }
  134. return *this;
  135. }
  136. Optional& operator=(Optional&& other)
  137. {
  138. if (this != &other) {
  139. clear();
  140. m_value = other.m_value;
  141. }
  142. return *this;
  143. }
  144. void clear()
  145. {
  146. m_value = JS::Completion(JS::Completion::EmptyTag {});
  147. }
  148. [[nodiscard]] bool has_value() const
  149. {
  150. return !m_value.is_empty();
  151. }
  152. [[nodiscard]] JS::Completion& value() &
  153. {
  154. VERIFY(has_value());
  155. return m_value;
  156. }
  157. [[nodiscard]] JS::Completion const& value() const&
  158. {
  159. VERIFY(has_value());
  160. return m_value;
  161. }
  162. [[nodiscard]] JS::Completion value() &&
  163. {
  164. return release_value();
  165. }
  166. [[nodiscard]] JS::Completion release_value()
  167. {
  168. VERIFY(has_value());
  169. JS::Completion released_value = m_value;
  170. clear();
  171. return released_value;
  172. }
  173. JS::Completion value_or(JS::Completion const& fallback) const&
  174. {
  175. if (has_value())
  176. return value();
  177. return fallback;
  178. }
  179. [[nodiscard]] JS::Completion value_or(JS::Completion&& fallback) &&
  180. {
  181. if (has_value())
  182. return value();
  183. return fallback;
  184. }
  185. JS::Completion const& operator*() const { return value(); }
  186. JS::Completion& operator*() { return value(); }
  187. JS::Completion const* operator->() const { return &value(); }
  188. JS::Completion* operator->() { return &value(); }
  189. private:
  190. JS::Completion m_value;
  191. };
  192. }
  193. namespace JS {
  194. template<typename ValueType>
  195. class [[nodiscard]] ThrowCompletionOr {
  196. public:
  197. ThrowCompletionOr()
  198. requires(IsSame<ValueType, Empty>)
  199. : m_value(Empty {})
  200. {
  201. }
  202. // Not `explicit` on purpose so that `return vm.throw_completion<Error>(...);` is possible.
  203. ThrowCompletionOr(Completion throw_completion)
  204. : m_throw_completion(move(throw_completion))
  205. {
  206. VERIFY(m_throw_completion->is_error());
  207. }
  208. // Not `explicit` on purpose so that `return value;` is possible.
  209. ThrowCompletionOr(ValueType value)
  210. : m_value(move(value))
  211. {
  212. if constexpr (IsSame<ValueType, Value>)
  213. VERIFY(!m_value->is_empty());
  214. }
  215. ThrowCompletionOr(ThrowCompletionOr const&) = default;
  216. ThrowCompletionOr& operator=(ThrowCompletionOr const&) = default;
  217. ThrowCompletionOr(ThrowCompletionOr&&) = default;
  218. ThrowCompletionOr& operator=(ThrowCompletionOr&&) = default;
  219. // Allows implicit construction of ThrowCompletionOr<T> from a type U if T(U) is a supported constructor.
  220. // Most commonly: Value from Object* or similar, so we can omit the curly braces from "return { TRY(...) };".
  221. // Disabled for POD types to avoid weird conversion shenanigans.
  222. template<typename WrappedValueType>
  223. ThrowCompletionOr(WrappedValueType const& value)
  224. requires(!IsPOD<ValueType>)
  225. : m_value(value)
  226. {
  227. }
  228. [[nodiscard]] bool is_throw_completion() const { return m_throw_completion.has_value(); }
  229. Completion const& throw_completion() const { return *m_throw_completion; }
  230. [[nodiscard]] bool has_value() const
  231. requires(!IsSame<ValueType, Empty>)
  232. {
  233. return m_value.has_value();
  234. }
  235. [[nodiscard]] ValueType const& value() const
  236. requires(!IsSame<ValueType, Empty>)
  237. {
  238. return *m_value;
  239. }
  240. // These are for compatibility with the TRY() macro in AK.
  241. [[nodiscard]] bool is_error() const { return m_throw_completion.has_value(); }
  242. [[nodiscard]] ValueType release_value() { return m_value.release_value(); }
  243. Completion release_error() { return m_throw_completion.release_value(); }
  244. private:
  245. Optional<Completion> m_throw_completion;
  246. Optional<ValueType> m_value;
  247. };
  248. template<>
  249. class ThrowCompletionOr<void> : public ThrowCompletionOr<Empty> {
  250. public:
  251. using ThrowCompletionOr<Empty>::ThrowCompletionOr;
  252. };
  253. ThrowCompletionOr<Value> await(VM&, Value);
  254. // 6.2.3.2 NormalCompletion ( value ), https://tc39.es/ecma262/#sec-normalcompletion
  255. inline Completion normal_completion(Optional<Value> value)
  256. {
  257. return { Completion::Type::Normal, move(value), {} };
  258. }
  259. // 6.2.3.3 ThrowCompletion ( value ), https://tc39.es/ecma262/#sec-throwcompletion
  260. Completion throw_completion(Value);
  261. }