Completion.h 13 KB

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