Print.cpp 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017
  1. /*
  2. * Copyright (c) 2020-2021, Andreas Kling <andreas@ladybird.org>
  3. * Copyright (c) 2020-2022, Linus Groh <linusg@serenityos.org>
  4. * Copyright (c) 2022, Ali Mohammad Pur <mpfard@serenityos.org>
  5. *
  6. * SPDX-License-Identifier: BSD-2-Clause
  7. */
  8. #include <AK/Concepts.h>
  9. #include <AK/Stream.h>
  10. #include <LibJS/Print.h>
  11. #include <LibJS/Runtime/Array.h>
  12. #include <LibJS/Runtime/ArrayBuffer.h>
  13. #include <LibJS/Runtime/AsyncGenerator.h>
  14. #include <LibJS/Runtime/BooleanObject.h>
  15. #include <LibJS/Runtime/ConsoleObject.h>
  16. #include <LibJS/Runtime/DataView.h>
  17. #include <LibJS/Runtime/Date.h>
  18. #include <LibJS/Runtime/DatePrototype.h>
  19. #include <LibJS/Runtime/ECMAScriptFunctionObject.h>
  20. #include <LibJS/Runtime/Error.h>
  21. #include <LibJS/Runtime/FunctionObject.h>
  22. #include <LibJS/Runtime/GeneratorObject.h>
  23. #include <LibJS/Runtime/GlobalObject.h>
  24. #include <LibJS/Runtime/Intl/Collator.h>
  25. #include <LibJS/Runtime/Intl/DateTimeFormat.h>
  26. #include <LibJS/Runtime/Intl/DisplayNames.h>
  27. #include <LibJS/Runtime/Intl/DurationFormat.h>
  28. #include <LibJS/Runtime/Intl/ListFormat.h>
  29. #include <LibJS/Runtime/Intl/Locale.h>
  30. #include <LibJS/Runtime/Intl/NumberFormat.h>
  31. #include <LibJS/Runtime/Intl/PluralRules.h>
  32. #include <LibJS/Runtime/Intl/RelativeTimeFormat.h>
  33. #include <LibJS/Runtime/Intl/Segmenter.h>
  34. #include <LibJS/Runtime/Intl/Segments.h>
  35. #include <LibJS/Runtime/JSONObject.h>
  36. #include <LibJS/Runtime/Map.h>
  37. #include <LibJS/Runtime/NativeFunction.h>
  38. #include <LibJS/Runtime/NumberObject.h>
  39. #include <LibJS/Runtime/Object.h>
  40. #include <LibJS/Runtime/PrimitiveString.h>
  41. #include <LibJS/Runtime/Promise.h>
  42. #include <LibJS/Runtime/ProxyObject.h>
  43. #include <LibJS/Runtime/RegExpObject.h>
  44. #include <LibJS/Runtime/Set.h>
  45. #include <LibJS/Runtime/ShadowRealm.h>
  46. #include <LibJS/Runtime/Shape.h>
  47. #include <LibJS/Runtime/StringObject.h>
  48. #include <LibJS/Runtime/StringPrototype.h>
  49. #include <LibJS/Runtime/Temporal/Duration.h>
  50. #include <LibJS/Runtime/Temporal/PlainMonthDay.h>
  51. #include <LibJS/Runtime/Temporal/PlainYearMonth.h>
  52. #include <LibJS/Runtime/TypedArray.h>
  53. #include <LibJS/Runtime/Value.h>
  54. #include <LibJS/Runtime/WeakMap.h>
  55. #include <LibJS/Runtime/WeakRef.h>
  56. #include <LibJS/Runtime/WeakSet.h>
  57. namespace {
  58. static ErrorOr<String> escape_for_string_literal(StringView string)
  59. {
  60. StringBuilder builder;
  61. for (auto byte : string.bytes()) {
  62. switch (byte) {
  63. case '\r':
  64. TRY(builder.try_append("\\r"sv));
  65. continue;
  66. case '\v':
  67. TRY(builder.try_append("\\v"sv));
  68. continue;
  69. case '\f':
  70. TRY(builder.try_append("\\f"sv));
  71. continue;
  72. case '\b':
  73. TRY(builder.try_append("\\b"sv));
  74. continue;
  75. case '\n':
  76. TRY(builder.try_append("\\n"sv));
  77. continue;
  78. case '\\':
  79. TRY(builder.try_append("\\\\"sv));
  80. continue;
  81. default:
  82. TRY(builder.try_append(byte));
  83. continue;
  84. }
  85. }
  86. return builder.to_string();
  87. }
  88. ErrorOr<void> print_value(JS::PrintContext&, JS::Value value, HashTable<JS::Object*>& seen_objects);
  89. template<typename T>
  90. ErrorOr<void> print_value(JS::PrintContext& print_context, JS::ThrowCompletionOr<T> value_or_error, HashTable<JS::Object*>& seen_objects)
  91. {
  92. if (value_or_error.is_error()) {
  93. auto error = value_or_error.release_error();
  94. // We can't explicitly check for OOM because InternalError does not store the ErrorType
  95. VERIFY(error.value().has_value());
  96. VERIFY(error.value()->is_object());
  97. VERIFY(is<JS::InternalError>(error.value()->as_object()));
  98. return Error::from_errno(ENOMEM);
  99. }
  100. return print_value(print_context, value_or_error.release_value(), seen_objects);
  101. }
  102. ErrorOr<String> strip_ansi(StringView format_string)
  103. {
  104. if (format_string.is_empty())
  105. return String();
  106. StringBuilder builder;
  107. size_t i;
  108. for (i = 0; i < format_string.length() - 1; ++i) {
  109. if (format_string[i] == '\033' && format_string[i + 1] == '[') {
  110. while (i < format_string.length() && format_string[i] != 'm')
  111. ++i;
  112. } else {
  113. TRY(builder.try_append(format_string[i]));
  114. }
  115. }
  116. if (i < format_string.length())
  117. TRY(builder.try_append(format_string[i]));
  118. return builder.to_string();
  119. }
  120. template<typename... Args>
  121. ErrorOr<void> js_out(JS::PrintContext& print_context, CheckedFormatString<Args...> format_string, Args const&... args)
  122. {
  123. if (print_context.strip_ansi) {
  124. auto format_string_without_ansi = TRY(strip_ansi(format_string.view()));
  125. TRY(print_context.stream.write_formatted(format_string_without_ansi, args...));
  126. } else {
  127. TRY(print_context.stream.write_formatted(format_string.view(), args...));
  128. }
  129. return {};
  130. }
  131. ErrorOr<void> print_type(JS::PrintContext& print_context, StringView name)
  132. {
  133. return js_out(print_context, "[\033[36;1m{}\033[0m]", name);
  134. }
  135. ErrorOr<void> print_separator(JS::PrintContext& print_context, bool& first)
  136. {
  137. TRY(js_out(print_context, first ? " "sv : ", "sv));
  138. first = false;
  139. return {};
  140. }
  141. ErrorOr<void> print_array(JS::PrintContext& print_context, JS::Array const& array, HashTable<JS::Object*>& seen_objects)
  142. {
  143. TRY(js_out(print_context, "["));
  144. bool first = true;
  145. size_t printed_count = 0;
  146. for (auto it = array.indexed_properties().begin(false); it != array.indexed_properties().end(); ++it) {
  147. TRY(print_separator(print_context, first));
  148. auto value_or_error = array.get(it.index());
  149. // The V8 repl doesn't throw an exception here, and instead just
  150. // prints 'undefined'. We may choose to replicate that behavior in
  151. // the future, but for now lets just catch the error
  152. if (value_or_error.is_error())
  153. return {};
  154. auto value = value_or_error.release_value();
  155. TRY(print_value(print_context, value, seen_objects));
  156. if (++printed_count > 100 && it != array.indexed_properties().end()) {
  157. TRY(js_out(print_context, ", ..."));
  158. break;
  159. }
  160. }
  161. if (!first)
  162. TRY(js_out(print_context, " "));
  163. TRY(js_out(print_context, "]"));
  164. return {};
  165. }
  166. ErrorOr<void> print_object(JS::PrintContext& print_context, JS::Object const& object, HashTable<JS::Object*>& seen_objects)
  167. {
  168. TRY(js_out(print_context, "{}{{", object.class_name()));
  169. bool first = true;
  170. static constexpr size_t max_number_of_new_objects = 20; // Arbitrary limit
  171. size_t original_num_seen_objects = seen_objects.size();
  172. auto maybe_completion = object.enumerate_object_properties([&](JS::Value property_key) -> Optional<JS::Completion> {
  173. // The V8 repl doesn't throw an exception on accessing properties, and instead just
  174. // prints 'undefined'. We may choose to replicate that behavior in
  175. // the future, but for now lets just catch the error
  176. auto error = print_separator(print_context, first);
  177. if (error.is_error())
  178. return JS::js_undefined();
  179. error = js_out(print_context, "\033[33;1m");
  180. if (error.is_error())
  181. return JS::js_undefined();
  182. error = print_value(print_context, property_key, seen_objects);
  183. // NOTE: Ignore this error to always print out "reset" ANSI sequence
  184. error = js_out(print_context, "\033[0m: ");
  185. if (error.is_error())
  186. return JS::js_undefined();
  187. auto maybe_property_key = JS::PropertyKey::from_value(print_context.vm, property_key);
  188. if (maybe_property_key.is_error())
  189. return JS::js_undefined();
  190. auto value_or_error = object.get(maybe_property_key.value());
  191. if (value_or_error.is_error())
  192. return JS::js_undefined();
  193. auto value = value_or_error.release_value();
  194. error = print_value(print_context, value, seen_objects);
  195. // FIXME: Come up with a better way to structure the data so that we don't care about this limit
  196. if (seen_objects.size() > original_num_seen_objects + max_number_of_new_objects)
  197. return JS::js_undefined(); // Stop once we've seen a ton of objects, to prevent spamming the console.
  198. if (error.is_error())
  199. return JS::js_undefined();
  200. return {};
  201. });
  202. // Swallow Error/undefined from printing properties
  203. if (maybe_completion.has_value())
  204. return {};
  205. if (!first)
  206. TRY(js_out(print_context, " "));
  207. TRY(js_out(print_context, "}}"));
  208. return {};
  209. }
  210. ErrorOr<void> print_function(JS::PrintContext& print_context, JS::FunctionObject const& function_object, HashTable<JS::Object*>&)
  211. {
  212. if (is<JS::ECMAScriptFunctionObject>(function_object)) {
  213. auto const& ecmascript_function_object = static_cast<JS::ECMAScriptFunctionObject const&>(function_object);
  214. switch (ecmascript_function_object.kind()) {
  215. case JS::FunctionKind::Normal:
  216. TRY(print_type(print_context, "Function"sv));
  217. break;
  218. case JS::FunctionKind::Generator:
  219. TRY(print_type(print_context, "GeneratorFunction"sv));
  220. break;
  221. case JS::FunctionKind::Async:
  222. TRY(print_type(print_context, "AsyncFunction"sv));
  223. break;
  224. case JS::FunctionKind::AsyncGenerator:
  225. TRY(print_type(print_context, "AsyncGeneratorFunction"sv));
  226. break;
  227. default:
  228. VERIFY_NOT_REACHED();
  229. }
  230. } else {
  231. TRY(print_type(print_context, function_object.class_name()));
  232. }
  233. if (is<JS::ECMAScriptFunctionObject>(function_object))
  234. TRY(js_out(print_context, " {}", static_cast<JS::ECMAScriptFunctionObject const&>(function_object).name()));
  235. else if (is<JS::NativeFunction>(function_object))
  236. TRY(js_out(print_context, " {}", static_cast<JS::NativeFunction const&>(function_object).name()));
  237. return {};
  238. }
  239. ErrorOr<void> print_date(JS::PrintContext& print_context, JS::Date const& date, HashTable<JS::Object*>&)
  240. {
  241. TRY(print_type(print_context, "Date"sv));
  242. TRY(js_out(print_context, " \033[34;1m{}\033[0m", JS::to_date_string(date.date_value())));
  243. return {};
  244. }
  245. ErrorOr<void> print_error(JS::PrintContext& print_context, JS::Object const& object, HashTable<JS::Object*>& seen_objects)
  246. {
  247. auto name = object.get_without_side_effects(print_context.vm.names.name).value_or(JS::js_undefined());
  248. auto message = object.get_without_side_effects(print_context.vm.names.message).value_or(JS::js_undefined());
  249. if (name.is_accessor() || message.is_accessor()) {
  250. TRY(print_value(print_context, &object, seen_objects));
  251. } else {
  252. auto name_string = name.to_string_without_side_effects();
  253. auto message_string = message.to_string_without_side_effects();
  254. TRY(print_type(print_context, name_string));
  255. if (!message_string.is_empty())
  256. TRY(js_out(print_context, " \033[31;1m{}\033[0m", message_string));
  257. }
  258. return {};
  259. }
  260. ErrorOr<void> print_regexp_object(JS::PrintContext& print_context, JS::RegExpObject const& regexp_object, HashTable<JS::Object*>&)
  261. {
  262. TRY(print_type(print_context, "RegExp"sv));
  263. TRY(js_out(print_context, " \033[34;1m/{}/{}\033[0m", regexp_object.escape_regexp_pattern(), regexp_object.flags()));
  264. return {};
  265. }
  266. ErrorOr<void> print_proxy_object(JS::PrintContext& print_context, JS::ProxyObject const& proxy_object, HashTable<JS::Object*>& seen_objects)
  267. {
  268. TRY(print_type(print_context, "Proxy"sv));
  269. TRY(js_out(print_context, "\n target: "));
  270. TRY(print_value(print_context, &proxy_object.target(), seen_objects));
  271. TRY(js_out(print_context, "\n handler: "));
  272. TRY(print_value(print_context, &proxy_object.handler(), seen_objects));
  273. return {};
  274. }
  275. ErrorOr<void> print_map(JS::PrintContext& print_context, JS::Map const& map, HashTable<JS::Object*>& seen_objects)
  276. {
  277. TRY(print_type(print_context, "Map"sv));
  278. TRY(js_out(print_context, " {{"));
  279. bool first = true;
  280. for (auto const& entry : map) {
  281. TRY(print_separator(print_context, first));
  282. TRY(print_value(print_context, entry.key, seen_objects));
  283. TRY(js_out(print_context, " => "));
  284. TRY(print_value(print_context, entry.value, seen_objects));
  285. }
  286. if (!first)
  287. TRY(js_out(print_context, " "));
  288. TRY(js_out(print_context, "}}"));
  289. return {};
  290. }
  291. ErrorOr<void> print_set(JS::PrintContext& print_context, JS::Set const& set, HashTable<JS::Object*>& seen_objects)
  292. {
  293. TRY(print_type(print_context, "Set"sv));
  294. TRY(js_out(print_context, " {{"));
  295. bool first = true;
  296. for (auto const& entry : set) {
  297. TRY(print_separator(print_context, first));
  298. TRY(print_value(print_context, entry.key, seen_objects));
  299. }
  300. if (!first)
  301. TRY(js_out(print_context, " "));
  302. TRY(js_out(print_context, "}}"));
  303. return {};
  304. }
  305. ErrorOr<void> print_weak_map(JS::PrintContext& print_context, JS::WeakMap const& weak_map, HashTable<JS::Object*>&)
  306. {
  307. TRY(print_type(print_context, "WeakMap"sv));
  308. TRY(js_out(print_context, " ({})", weak_map.values().size()));
  309. // Note: We could tell you what's actually inside, but not in insertion order.
  310. return {};
  311. }
  312. ErrorOr<void> print_weak_set(JS::PrintContext& print_context, JS::WeakSet const& weak_set, HashTable<JS::Object*>&)
  313. {
  314. TRY(print_type(print_context, "WeakSet"sv));
  315. TRY(js_out(print_context, " ({})", weak_set.values().size()));
  316. // Note: We could tell you what's actually inside, but not in insertion order.
  317. return {};
  318. }
  319. ErrorOr<void> print_weak_ref(JS::PrintContext& print_context, JS::WeakRef const& weak_ref, HashTable<JS::Object*>& seen_objects)
  320. {
  321. TRY(print_type(print_context, "WeakRef"sv));
  322. TRY(js_out(print_context, " "));
  323. TRY(print_value(print_context, weak_ref.value().visit([](Empty) -> JS::Value { return JS::js_undefined(); }, [](auto value) -> JS::Value { return value; }), seen_objects));
  324. return {};
  325. }
  326. ErrorOr<void> print_promise(JS::PrintContext& print_context, JS::Promise const& promise, HashTable<JS::Object*>& seen_objects)
  327. {
  328. TRY(print_type(print_context, "Promise"sv));
  329. switch (promise.state()) {
  330. case JS::Promise::State::Pending:
  331. TRY(js_out(print_context, "\n state: "));
  332. TRY(js_out(print_context, "\033[36;1mPending\033[0m"));
  333. break;
  334. case JS::Promise::State::Fulfilled:
  335. TRY(js_out(print_context, "\n state: "));
  336. TRY(js_out(print_context, "\033[32;1mFulfilled\033[0m"));
  337. TRY(js_out(print_context, "\n result: "));
  338. TRY(print_value(print_context, promise.result(), seen_objects));
  339. break;
  340. case JS::Promise::State::Rejected:
  341. TRY(js_out(print_context, "\n state: "));
  342. TRY(js_out(print_context, "\033[31;1mRejected\033[0m"));
  343. TRY(js_out(print_context, "\n result: "));
  344. TRY(print_value(print_context, promise.result(), seen_objects));
  345. break;
  346. default:
  347. VERIFY_NOT_REACHED();
  348. }
  349. return {};
  350. }
  351. ErrorOr<void> print_array_buffer(JS::PrintContext& print_context, JS::ArrayBuffer const& array_buffer, HashTable<JS::Object*>& seen_objects)
  352. {
  353. TRY(print_type(print_context, "ArrayBuffer"sv));
  354. auto byte_length = array_buffer.byte_length();
  355. TRY(js_out(print_context, "\n byteLength: "));
  356. TRY(print_value(print_context, JS::Value((double)byte_length), seen_objects));
  357. if (array_buffer.is_detached()) {
  358. TRY(js_out(print_context, "\n Detached"));
  359. return {};
  360. }
  361. if (byte_length == 0)
  362. return {};
  363. auto& buffer = array_buffer.buffer();
  364. TRY(js_out(print_context, "\n"));
  365. for (size_t i = 0; i < byte_length; ++i) {
  366. TRY(js_out(print_context, "{:02x}", buffer[i]));
  367. if (i + 1 < byte_length) {
  368. if ((i + 1) % 32 == 0)
  369. TRY(js_out(print_context, "\n"));
  370. else if ((i + 1) % 16 == 0)
  371. TRY(js_out(print_context, " "));
  372. else
  373. TRY(js_out(print_context, " "));
  374. }
  375. }
  376. return {};
  377. }
  378. ErrorOr<void> print_shadow_realm(JS::PrintContext& print_context, JS::ShadowRealm const&, HashTable<JS::Object*>&)
  379. {
  380. // Not much we can show here that would be useful. Realm pointer address?!
  381. TRY(print_type(print_context, "ShadowRealm"sv));
  382. return {};
  383. }
  384. ErrorOr<void> print_generator(JS::PrintContext& print_context, JS::GeneratorObject const& generator, HashTable<JS::Object*>&)
  385. {
  386. TRY(print_type(print_context, generator.class_name()));
  387. return {};
  388. }
  389. ErrorOr<void> print_async_generator(JS::PrintContext& print_context, JS::AsyncGenerator const& generator, HashTable<JS::Object*>&)
  390. {
  391. TRY(print_type(print_context, generator.class_name()));
  392. return {};
  393. }
  394. template<Arithmetic T>
  395. ErrorOr<void> print_number(JS::PrintContext& print_context, T number)
  396. {
  397. TRY(js_out(print_context, "\033[35;1m"));
  398. TRY(js_out(print_context, "{}", number));
  399. TRY(js_out(print_context, "\033[0m"));
  400. return {};
  401. }
  402. ErrorOr<void> print_typed_array(JS::PrintContext& print_context, JS::TypedArrayBase const& typed_array_base, HashTable<JS::Object*>& seen_objects)
  403. {
  404. auto& array_buffer = *typed_array_base.viewed_array_buffer();
  405. auto typed_array_record = JS::make_typed_array_with_buffer_witness_record(typed_array_base, JS::ArrayBuffer::Order::SeqCst);
  406. TRY(print_type(print_context, typed_array_base.class_name()));
  407. TRY(js_out(print_context, "\n buffer: "));
  408. TRY(print_type(print_context, "ArrayBuffer"sv));
  409. TRY(js_out(print_context, " @ {:p}", &array_buffer));
  410. if (JS::is_typed_array_out_of_bounds(typed_array_record)) {
  411. TRY(js_out(print_context, "\n <out of bounds>"));
  412. return {};
  413. }
  414. auto length = JS::typed_array_length(typed_array_record);
  415. TRY(js_out(print_context, "\n length: "));
  416. TRY(print_value(print_context, JS::Value(length), seen_objects));
  417. TRY(js_out(print_context, "\n byteLength: "));
  418. TRY(print_value(print_context, JS::Value(JS::typed_array_byte_length(typed_array_record)), seen_objects));
  419. TRY(js_out(print_context, "\n"));
  420. // FIXME: This kinda sucks.
  421. #define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
  422. if (is<JS::ClassName>(typed_array_base)) { \
  423. TRY(js_out(print_context, "[ ")); \
  424. auto& typed_array = static_cast<JS::ClassName const&>(typed_array_base); \
  425. auto data = typed_array.data(); \
  426. size_t printed_count = 0; \
  427. for (size_t i = 0; i < length; ++i) { \
  428. if (i > 0) \
  429. TRY(js_out(print_context, ", ")); \
  430. TRY(print_number(print_context, data[i])); \
  431. if (++printed_count > 100 && i < length) { \
  432. TRY(js_out(print_context, ", ...")); \
  433. break; \
  434. } \
  435. } \
  436. TRY(js_out(print_context, " ]")); \
  437. return {}; \
  438. }
  439. JS_ENUMERATE_TYPED_ARRAYS
  440. #undef __JS_ENUMERATE
  441. VERIFY_NOT_REACHED();
  442. }
  443. ErrorOr<void> print_data_view(JS::PrintContext& print_context, JS::DataView const& data_view, HashTable<JS::Object*>& seen_objects)
  444. {
  445. auto view_record = JS::make_data_view_with_buffer_witness_record(data_view, JS::ArrayBuffer::Order::SeqCst);
  446. TRY(print_type(print_context, "DataView"sv));
  447. TRY(js_out(print_context, "\n buffer: "));
  448. TRY(print_type(print_context, "ArrayBuffer"sv));
  449. TRY(js_out(print_context, " @ {:p}", data_view.viewed_array_buffer()));
  450. if (JS::is_view_out_of_bounds(view_record)) {
  451. TRY(js_out(print_context, "\n <out of bounds>"));
  452. return {};
  453. }
  454. TRY(js_out(print_context, "\n byteLength: "));
  455. TRY(print_value(print_context, JS::Value(JS::get_view_byte_length(view_record)), seen_objects));
  456. TRY(js_out(print_context, "\n byteOffset: "));
  457. TRY(print_value(print_context, JS::Value(data_view.byte_offset()), seen_objects));
  458. return {};
  459. }
  460. ErrorOr<void> print_intl_display_names(JS::PrintContext& print_context, JS::Intl::DisplayNames const& display_names, HashTable<JS::Object*>& seen_objects)
  461. {
  462. TRY(print_type(print_context, "Intl.DisplayNames"sv));
  463. TRY(js_out(print_context, "\n locale: "));
  464. TRY(print_value(print_context, JS::PrimitiveString::create(display_names.vm(), display_names.locale()), seen_objects));
  465. TRY(js_out(print_context, "\n type: "));
  466. TRY(print_value(print_context, JS::PrimitiveString::create(display_names.vm(), display_names.type_string()), seen_objects));
  467. TRY(js_out(print_context, "\n style: "));
  468. TRY(print_value(print_context, JS::PrimitiveString::create(display_names.vm(), display_names.style_string()), seen_objects));
  469. TRY(js_out(print_context, "\n fallback: "));
  470. TRY(print_value(print_context, JS::PrimitiveString::create(display_names.vm(), display_names.fallback_string()), seen_objects));
  471. if (display_names.has_language_display()) {
  472. TRY(js_out(print_context, "\n languageDisplay: "));
  473. TRY(print_value(print_context, JS::PrimitiveString::create(display_names.vm(), display_names.language_display_string()), seen_objects));
  474. }
  475. return {};
  476. }
  477. ErrorOr<void> print_intl_locale(JS::PrintContext& print_context, JS::Intl::Locale const& locale, HashTable<JS::Object*>& seen_objects)
  478. {
  479. TRY(print_type(print_context, "Intl.Locale"sv));
  480. TRY(js_out(print_context, "\n locale: "));
  481. TRY(print_value(print_context, JS::PrimitiveString::create(locale.vm(), locale.locale()), seen_objects));
  482. if (locale.has_calendar()) {
  483. TRY(js_out(print_context, "\n calendar: "));
  484. TRY(print_value(print_context, JS::PrimitiveString::create(locale.vm(), locale.calendar()), seen_objects));
  485. }
  486. if (locale.has_case_first()) {
  487. TRY(js_out(print_context, "\n caseFirst: "));
  488. TRY(print_value(print_context, JS::PrimitiveString::create(locale.vm(), locale.case_first()), seen_objects));
  489. }
  490. if (locale.has_collation()) {
  491. TRY(js_out(print_context, "\n collation: "));
  492. TRY(print_value(print_context, JS::PrimitiveString::create(locale.vm(), locale.collation()), seen_objects));
  493. }
  494. if (locale.has_hour_cycle()) {
  495. TRY(js_out(print_context, "\n hourCycle: "));
  496. TRY(print_value(print_context, JS::PrimitiveString::create(locale.vm(), locale.hour_cycle()), seen_objects));
  497. }
  498. if (locale.has_numbering_system()) {
  499. TRY(js_out(print_context, "\n numberingSystem: "));
  500. TRY(print_value(print_context, JS::PrimitiveString::create(locale.vm(), locale.numbering_system()), seen_objects));
  501. }
  502. TRY(js_out(print_context, "\n numeric: "));
  503. TRY(print_value(print_context, JS::Value(locale.numeric()), seen_objects));
  504. return {};
  505. }
  506. ErrorOr<void> print_intl_list_format(JS::PrintContext& print_context, JS::Intl::ListFormat const& list_format, HashTable<JS::Object*>& seen_objects)
  507. {
  508. TRY(print_type(print_context, "Intl.ListFormat"sv));
  509. TRY(js_out(print_context, "\n locale: "));
  510. TRY(print_value(print_context, JS::PrimitiveString::create(list_format.vm(), list_format.locale()), seen_objects));
  511. TRY(js_out(print_context, "\n type: "));
  512. TRY(print_value(print_context, JS::PrimitiveString::create(list_format.vm(), list_format.type_string()), seen_objects));
  513. TRY(js_out(print_context, "\n style: "));
  514. TRY(print_value(print_context, JS::PrimitiveString::create(list_format.vm(), list_format.style_string()), seen_objects));
  515. return {};
  516. }
  517. ErrorOr<void> print_intl_number_format(JS::PrintContext& print_context, JS::Intl::NumberFormat const& number_format, HashTable<JS::Object*>& seen_objects)
  518. {
  519. TRY(print_type(print_context, "Intl.NumberFormat"sv));
  520. TRY(js_out(print_context, "\n locale: "));
  521. TRY(print_value(print_context, JS::PrimitiveString::create(number_format.vm(), number_format.locale()), seen_objects));
  522. TRY(js_out(print_context, "\n numberingSystem: "));
  523. TRY(print_value(print_context, JS::PrimitiveString::create(number_format.vm(), number_format.numbering_system()), seen_objects));
  524. TRY(js_out(print_context, "\n style: "));
  525. TRY(print_value(print_context, JS::PrimitiveString::create(number_format.vm(), number_format.style_string()), seen_objects));
  526. if (number_format.has_currency()) {
  527. TRY(js_out(print_context, "\n currency: "));
  528. TRY(print_value(print_context, JS::PrimitiveString::create(number_format.vm(), number_format.currency()), seen_objects));
  529. }
  530. if (number_format.has_currency_display()) {
  531. TRY(js_out(print_context, "\n currencyDisplay: "));
  532. TRY(print_value(print_context, JS::PrimitiveString::create(number_format.vm(), number_format.currency_display_string()), seen_objects));
  533. }
  534. if (number_format.has_currency_sign()) {
  535. TRY(js_out(print_context, "\n currencySign: "));
  536. TRY(print_value(print_context, JS::PrimitiveString::create(number_format.vm(), number_format.currency_sign_string()), seen_objects));
  537. }
  538. if (number_format.has_unit()) {
  539. TRY(js_out(print_context, "\n unit: "));
  540. TRY(print_value(print_context, JS::PrimitiveString::create(number_format.vm(), number_format.unit()), seen_objects));
  541. }
  542. if (number_format.has_unit_display()) {
  543. TRY(js_out(print_context, "\n unitDisplay: "));
  544. TRY(print_value(print_context, JS::PrimitiveString::create(number_format.vm(), number_format.unit_display_string()), seen_objects));
  545. }
  546. TRY(js_out(print_context, "\n minimumIntegerDigits: "));
  547. TRY(print_value(print_context, JS::Value(number_format.min_integer_digits()), seen_objects));
  548. if (number_format.has_min_fraction_digits()) {
  549. TRY(js_out(print_context, "\n minimumFractionDigits: "));
  550. TRY(print_value(print_context, JS::Value(number_format.min_fraction_digits()), seen_objects));
  551. }
  552. if (number_format.has_max_fraction_digits()) {
  553. TRY(js_out(print_context, "\n maximumFractionDigits: "));
  554. TRY(print_value(print_context, JS::Value(number_format.max_fraction_digits()), seen_objects));
  555. }
  556. if (number_format.has_min_significant_digits()) {
  557. TRY(js_out(print_context, "\n minimumSignificantDigits: "));
  558. TRY(print_value(print_context, JS::Value(number_format.min_significant_digits()), seen_objects));
  559. }
  560. if (number_format.has_max_significant_digits()) {
  561. TRY(js_out(print_context, "\n maximumSignificantDigits: "));
  562. TRY(print_value(print_context, JS::Value(number_format.max_significant_digits()), seen_objects));
  563. }
  564. TRY(js_out(print_context, "\n useGrouping: "));
  565. TRY(print_value(print_context, number_format.use_grouping_to_value(number_format.vm()), seen_objects));
  566. TRY(js_out(print_context, "\n roundingType: "));
  567. TRY(print_value(print_context, JS::PrimitiveString::create(number_format.vm(), number_format.rounding_type_string()), seen_objects));
  568. TRY(js_out(print_context, "\n roundingMode: "));
  569. TRY(print_value(print_context, JS::PrimitiveString::create(number_format.vm(), number_format.rounding_mode_string()), seen_objects));
  570. TRY(js_out(print_context, "\n roundingIncrement: "));
  571. TRY(print_value(print_context, JS::Value(number_format.rounding_increment()), seen_objects));
  572. TRY(js_out(print_context, "\n notation: "));
  573. TRY(print_value(print_context, JS::PrimitiveString::create(number_format.vm(), number_format.notation_string()), seen_objects));
  574. if (number_format.has_compact_display()) {
  575. TRY(js_out(print_context, "\n compactDisplay: "));
  576. TRY(print_value(print_context, JS::PrimitiveString::create(number_format.vm(), number_format.compact_display_string()), seen_objects));
  577. }
  578. TRY(js_out(print_context, "\n signDisplay: "));
  579. TRY(print_value(print_context, JS::PrimitiveString::create(number_format.vm(), number_format.sign_display_string()), seen_objects));
  580. TRY(js_out(print_context, "\n trailingZeroDisplay: "));
  581. TRY(print_value(print_context, JS::PrimitiveString::create(number_format.vm(), number_format.trailing_zero_display_string()), seen_objects));
  582. return {};
  583. }
  584. ErrorOr<void> print_intl_date_time_format(JS::PrintContext& print_context, JS::Intl::DateTimeFormat& date_time_format, HashTable<JS::Object*>& seen_objects)
  585. {
  586. TRY(print_type(print_context, "Intl.DateTimeFormat"sv));
  587. TRY(js_out(print_context, "\n locale: "));
  588. TRY(print_value(print_context, JS::PrimitiveString::create(date_time_format.vm(), date_time_format.locale()), seen_objects));
  589. TRY(js_out(print_context, "\n calendar: "));
  590. TRY(print_value(print_context, JS::PrimitiveString::create(date_time_format.vm(), date_time_format.calendar()), seen_objects));
  591. TRY(js_out(print_context, "\n numberingSystem: "));
  592. TRY(print_value(print_context, JS::PrimitiveString::create(date_time_format.vm(), date_time_format.numbering_system()), seen_objects));
  593. if (auto const& hour_cycle = date_time_format.date_time_format().hour_cycle; hour_cycle.has_value()) {
  594. TRY(js_out(print_context, "\n hourCycle: "));
  595. TRY(print_value(print_context, JS::PrimitiveString::create(date_time_format.vm(), Unicode::hour_cycle_to_string(*hour_cycle)), seen_objects));
  596. }
  597. TRY(js_out(print_context, "\n timeZone: "));
  598. TRY(print_value(print_context, JS::PrimitiveString::create(date_time_format.vm(), date_time_format.time_zone()), seen_objects));
  599. if (date_time_format.has_date_style()) {
  600. TRY(js_out(print_context, "\n dateStyle: "));
  601. TRY(print_value(print_context, JS::PrimitiveString::create(date_time_format.vm(), date_time_format.date_style_string()), seen_objects));
  602. }
  603. if (date_time_format.has_time_style()) {
  604. TRY(js_out(print_context, "\n timeStyle: "));
  605. TRY(print_value(print_context, JS::PrimitiveString::create(date_time_format.vm(), date_time_format.time_style_string()), seen_objects));
  606. }
  607. auto result = JS::Intl::for_each_calendar_field(date_time_format.vm(), date_time_format.date_time_format(), [&](auto& option, auto const& property, auto const&) -> JS::ThrowCompletionOr<void> {
  608. using ValueType = typename RemoveReference<decltype(option)>::ValueType;
  609. if (!option.has_value())
  610. return {};
  611. // Note: We can't `TRY()` here as `for_each_calendar_field` expects a ThrowCompletionOr<T> instead of an ErrorOr<T>,
  612. // So the quickest way out is to generate a null throw completion (we handle the throw ourselves).
  613. if (js_out(print_context, "\n {}: ", property).is_error())
  614. return JS::throw_completion(JS::js_null());
  615. if constexpr (IsIntegral<ValueType>) {
  616. if (print_value(print_context, JS::Value(*option), seen_objects).is_error())
  617. return JS::throw_completion(JS::js_null());
  618. } else {
  619. auto name = Unicode::calendar_pattern_style_to_string(*option);
  620. if (print_value(print_context, JS::PrimitiveString::create(date_time_format.vm(), name), seen_objects).is_error())
  621. return JS::throw_completion(JS::js_null());
  622. }
  623. return {};
  624. });
  625. if (result.is_throw_completion() && result.throw_completion().value()->is_null())
  626. return Error::from_errno(ENOMEM); // probably
  627. return {};
  628. }
  629. ErrorOr<void> print_intl_relative_time_format(JS::PrintContext& print_context, JS::Intl::RelativeTimeFormat const& date_time_format, HashTable<JS::Object*>& seen_objects)
  630. {
  631. TRY(print_type(print_context, "Intl.RelativeTimeFormat"sv));
  632. TRY(js_out(print_context, "\n locale: "));
  633. TRY(print_value(print_context, JS::PrimitiveString::create(date_time_format.vm(), date_time_format.locale()), seen_objects));
  634. TRY(js_out(print_context, "\n numberingSystem: "));
  635. TRY(print_value(print_context, JS::PrimitiveString::create(date_time_format.vm(), date_time_format.numbering_system()), seen_objects));
  636. TRY(js_out(print_context, "\n style: "));
  637. TRY(print_value(print_context, JS::PrimitiveString::create(date_time_format.vm(), date_time_format.style_string()), seen_objects));
  638. TRY(js_out(print_context, "\n numeric: "));
  639. TRY(print_value(print_context, JS::PrimitiveString::create(date_time_format.vm(), date_time_format.numeric_string()), seen_objects));
  640. return {};
  641. }
  642. ErrorOr<void> print_intl_plural_rules(JS::PrintContext& print_context, JS::Intl::PluralRules const& plural_rules, HashTable<JS::Object*>& seen_objects)
  643. {
  644. TRY(print_type(print_context, "Intl.PluralRules"sv));
  645. TRY(js_out(print_context, "\n locale: "));
  646. TRY(print_value(print_context, JS::PrimitiveString::create(plural_rules.vm(), plural_rules.locale()), seen_objects));
  647. TRY(js_out(print_context, "\n type: "));
  648. TRY(print_value(print_context, JS::PrimitiveString::create(plural_rules.vm(), plural_rules.type_string()), seen_objects));
  649. TRY(js_out(print_context, "\n minimumIntegerDigits: "));
  650. TRY(print_value(print_context, JS::Value(plural_rules.min_integer_digits()), seen_objects));
  651. if (plural_rules.has_min_fraction_digits()) {
  652. TRY(js_out(print_context, "\n minimumFractionDigits: "));
  653. TRY(print_value(print_context, JS::Value(plural_rules.min_fraction_digits()), seen_objects));
  654. }
  655. if (plural_rules.has_max_fraction_digits()) {
  656. TRY(js_out(print_context, "\n maximumFractionDigits: "));
  657. TRY(print_value(print_context, JS::Value(plural_rules.max_fraction_digits()), seen_objects));
  658. }
  659. if (plural_rules.has_min_significant_digits()) {
  660. TRY(js_out(print_context, "\n minimumSignificantDigits: "));
  661. TRY(print_value(print_context, JS::Value(plural_rules.min_significant_digits()), seen_objects));
  662. }
  663. if (plural_rules.has_max_significant_digits()) {
  664. TRY(js_out(print_context, "\n maximumSignificantDigits: "));
  665. TRY(print_value(print_context, JS::Value(plural_rules.max_significant_digits()), seen_objects));
  666. }
  667. TRY(js_out(print_context, "\n roundingType: "));
  668. TRY(print_value(print_context, JS::PrimitiveString::create(plural_rules.vm(), plural_rules.rounding_type_string()), seen_objects));
  669. return {};
  670. }
  671. ErrorOr<void> print_intl_collator(JS::PrintContext& print_context, JS::Intl::Collator const& collator, HashTable<JS::Object*>& seen_objects)
  672. {
  673. TRY(print_type(print_context, "Intl.Collator"sv));
  674. out("\n locale: ");
  675. TRY(print_value(print_context, JS::PrimitiveString::create(collator.vm(), collator.locale()), seen_objects));
  676. out("\n usage: ");
  677. TRY(print_value(print_context, JS::PrimitiveString::create(collator.vm(), collator.usage_string()), seen_objects));
  678. out("\n sensitivity: ");
  679. TRY(print_value(print_context, JS::PrimitiveString::create(collator.vm(), collator.sensitivity_string()), seen_objects));
  680. out("\n caseFirst: ");
  681. TRY(print_value(print_context, JS::PrimitiveString::create(collator.vm(), collator.case_first_string()), seen_objects));
  682. out("\n collation: ");
  683. TRY(print_value(print_context, JS::PrimitiveString::create(collator.vm(), collator.collation()), seen_objects));
  684. out("\n ignorePunctuation: ");
  685. TRY(print_value(print_context, JS::Value(collator.ignore_punctuation()), seen_objects));
  686. out("\n numeric: ");
  687. TRY(print_value(print_context, JS::Value(collator.numeric()), seen_objects));
  688. return {};
  689. }
  690. ErrorOr<void> print_intl_segmenter(JS::PrintContext& print_context, JS::Intl::Segmenter const& segmenter, HashTable<JS::Object*>& seen_objects)
  691. {
  692. TRY(print_type(print_context, "Intl.Segmenter"sv));
  693. out("\n locale: ");
  694. TRY(print_value(print_context, JS::PrimitiveString::create(segmenter.vm(), segmenter.locale()), seen_objects));
  695. out("\n granularity: ");
  696. TRY(print_value(print_context, JS::PrimitiveString::create(segmenter.vm(), segmenter.segmenter_granularity_string()), seen_objects));
  697. return {};
  698. }
  699. ErrorOr<void> print_intl_segments(JS::PrintContext& print_context, JS::Intl::Segments const& segments, HashTable<JS::Object*>& seen_objects)
  700. {
  701. auto segments_string = JS::Utf16String::create(segments.segments_string());
  702. TRY(print_type(print_context, "Segments"sv));
  703. out("\n string: ");
  704. TRY(print_value(print_context, JS::PrimitiveString::create(segments.vm(), move(segments_string)), seen_objects));
  705. return {};
  706. }
  707. ErrorOr<void> print_intl_duration_format(JS::PrintContext& print_context, JS::Intl::DurationFormat const& duration_format, HashTable<JS::Object*>& seen_objects)
  708. {
  709. TRY(print_type(print_context, "Intl.DurationFormat"sv));
  710. out("\n locale: ");
  711. TRY(print_value(print_context, JS::PrimitiveString::create(duration_format.vm(), duration_format.locale()), seen_objects));
  712. out("\n numberingSystem: ");
  713. TRY(print_value(print_context, JS::PrimitiveString::create(duration_format.vm(), duration_format.numbering_system()), seen_objects));
  714. out("\n style: ");
  715. TRY(print_value(print_context, JS::PrimitiveString::create(duration_format.vm(), duration_format.style_string()), seen_objects));
  716. out("\n years: ");
  717. TRY(print_value(print_context, JS::PrimitiveString::create(duration_format.vm(), duration_format.years_style_string()), seen_objects));
  718. out("\n yearsDisplay: ");
  719. TRY(print_value(print_context, JS::PrimitiveString::create(duration_format.vm(), duration_format.years_display_string()), seen_objects));
  720. out("\n months: ");
  721. TRY(print_value(print_context, JS::PrimitiveString::create(duration_format.vm(), duration_format.months_style_string()), seen_objects));
  722. out("\n monthsDisplay: ");
  723. TRY(print_value(print_context, JS::PrimitiveString::create(duration_format.vm(), duration_format.months_display_string()), seen_objects));
  724. out("\n weeks: ");
  725. TRY(print_value(print_context, JS::PrimitiveString::create(duration_format.vm(), duration_format.weeks_style_string()), seen_objects));
  726. out("\n weeksDisplay: ");
  727. TRY(print_value(print_context, JS::PrimitiveString::create(duration_format.vm(), duration_format.weeks_display_string()), seen_objects));
  728. out("\n days: ");
  729. TRY(print_value(print_context, JS::PrimitiveString::create(duration_format.vm(), duration_format.days_style_string()), seen_objects));
  730. out("\n daysDisplay: ");
  731. TRY(print_value(print_context, JS::PrimitiveString::create(duration_format.vm(), duration_format.days_display_string()), seen_objects));
  732. out("\n hours: ");
  733. TRY(print_value(print_context, JS::PrimitiveString::create(duration_format.vm(), duration_format.hours_style_string()), seen_objects));
  734. out("\n hoursDisplay: ");
  735. TRY(print_value(print_context, JS::PrimitiveString::create(duration_format.vm(), duration_format.hours_display_string()), seen_objects));
  736. out("\n minutes: ");
  737. TRY(print_value(print_context, JS::PrimitiveString::create(duration_format.vm(), duration_format.minutes_style_string()), seen_objects));
  738. out("\n minutesDisplay: ");
  739. TRY(print_value(print_context, JS::PrimitiveString::create(duration_format.vm(), duration_format.minutes_display_string()), seen_objects));
  740. out("\n seconds: ");
  741. TRY(print_value(print_context, JS::PrimitiveString::create(duration_format.vm(), duration_format.seconds_style_string()), seen_objects));
  742. out("\n secondsDisplay: ");
  743. TRY(print_value(print_context, JS::PrimitiveString::create(duration_format.vm(), duration_format.seconds_display_string()), seen_objects));
  744. out("\n milliseconds: ");
  745. TRY(print_value(print_context, JS::PrimitiveString::create(duration_format.vm(), duration_format.milliseconds_style_string()), seen_objects));
  746. out("\n millisecondsDisplay: ");
  747. TRY(print_value(print_context, JS::PrimitiveString::create(duration_format.vm(), duration_format.milliseconds_display_string()), seen_objects));
  748. out("\n microseconds: ");
  749. TRY(print_value(print_context, JS::PrimitiveString::create(duration_format.vm(), duration_format.microseconds_style_string()), seen_objects));
  750. out("\n microsecondsDisplay: ");
  751. TRY(print_value(print_context, JS::PrimitiveString::create(duration_format.vm(), duration_format.microseconds_display_string()), seen_objects));
  752. out("\n nanoseconds: ");
  753. TRY(print_value(print_context, JS::PrimitiveString::create(duration_format.vm(), duration_format.nanoseconds_style_string()), seen_objects));
  754. out("\n nanosecondsDisplay: ");
  755. TRY(print_value(print_context, JS::PrimitiveString::create(duration_format.vm(), duration_format.nanoseconds_display_string()), seen_objects));
  756. if (duration_format.has_fractional_digits()) {
  757. out("\n fractionalDigits: ");
  758. TRY(print_value(print_context, JS::Value(duration_format.fractional_digits()), seen_objects));
  759. }
  760. return {};
  761. }
  762. ErrorOr<void> print_temporal_duration(JS::PrintContext& print_context, JS::Temporal::Duration const& duration, HashTable<JS::Object*>&)
  763. {
  764. TRY(print_type(print_context, "Temporal.Duration"sv));
  765. TRY(js_out(print_context, " \033[34;1m{} y, {} M, {} w, {} d, {} h, {} m, {} s, {} ms, {} us, {} ns\033[0m", duration.years(), duration.months(), duration.weeks(), duration.days(), duration.hours(), duration.minutes(), duration.seconds(), duration.milliseconds(), duration.microseconds(), duration.nanoseconds()));
  766. return {};
  767. }
  768. ErrorOr<void> print_temporal_plain_month_day(JS::PrintContext& print_context, JS::Temporal::PlainMonthDay const& plain_month_day, HashTable<JS::Object*>& seen_objects)
  769. {
  770. TRY(print_type(print_context, "Temporal.PlainMonthDay"sv));
  771. TRY(js_out(print_context, " \033[34;1m{:02}-{:02}\033[0m", plain_month_day.iso_date().month, plain_month_day.iso_date().day));
  772. TRY(js_out(print_context, "\n calendar: "));
  773. TRY(print_value(print_context, JS::PrimitiveString::create(plain_month_day.vm(), plain_month_day.calendar()), seen_objects));
  774. return {};
  775. }
  776. ErrorOr<void> print_temporal_plain_year_month(JS::PrintContext& print_context, JS::Temporal::PlainYearMonth const& plain_year_month, HashTable<JS::Object*>& seen_objects)
  777. {
  778. TRY(print_type(print_context, "Temporal.PlainYearMonth"sv));
  779. TRY(js_out(print_context, " \033[34;1m{:04}-{:02}\033[0m", plain_year_month.iso_date().year, plain_year_month.iso_date().month));
  780. TRY(js_out(print_context, "\n calendar: "));
  781. TRY(print_value(print_context, JS::PrimitiveString::create(plain_year_month.vm(), plain_year_month.calendar()), seen_objects));
  782. return {};
  783. }
  784. ErrorOr<void> print_boolean_object(JS::PrintContext& print_context, JS::BooleanObject const& boolean_object, HashTable<JS::Object*>& seen_objects)
  785. {
  786. TRY(print_type(print_context, "Boolean"sv));
  787. TRY(js_out(print_context, " "));
  788. TRY(print_value(print_context, JS::Value(boolean_object.boolean()), seen_objects));
  789. return {};
  790. }
  791. ErrorOr<void> print_number_object(JS::PrintContext& print_context, JS::NumberObject const& number_object, HashTable<JS::Object*>& seen_objects)
  792. {
  793. TRY(print_type(print_context, "Number"sv));
  794. TRY(js_out(print_context, " "));
  795. TRY(print_value(print_context, JS::Value(number_object.number()), seen_objects));
  796. return {};
  797. }
  798. ErrorOr<void> print_string_object(JS::PrintContext& print_context, JS::StringObject const& string_object, HashTable<JS::Object*>& seen_objects)
  799. {
  800. TRY(print_type(print_context, "String"sv));
  801. TRY(js_out(print_context, " "));
  802. TRY(print_value(print_context, &string_object.primitive_string(), seen_objects));
  803. return {};
  804. }
  805. ErrorOr<void> print_value(JS::PrintContext& print_context, JS::Value value, HashTable<JS::Object*>& seen_objects)
  806. {
  807. if (value.is_empty()) {
  808. TRY(js_out(print_context, "\033[34;1m<empty>\033[0m"));
  809. return {};
  810. }
  811. if (value.is_object()) {
  812. if (seen_objects.contains(&value.as_object())) {
  813. // FIXME: Maybe we should only do this for circular references,
  814. // not for all reoccurring objects.
  815. TRY(js_out(print_context, "<already printed Object {}>", &value.as_object()));
  816. return {};
  817. }
  818. seen_objects.set(&value.as_object());
  819. }
  820. if (value.is_object()) {
  821. auto& object = value.as_object();
  822. if (is<JS::Array>(object))
  823. return print_array(print_context, static_cast<JS::Array&>(object), seen_objects);
  824. if (object.is_function())
  825. return print_function(print_context, static_cast<JS::FunctionObject&>(object), seen_objects);
  826. if (is<JS::Date>(object))
  827. return print_date(print_context, static_cast<JS::Date&>(object), seen_objects);
  828. if (is<JS::Error>(object))
  829. return print_error(print_context, object, seen_objects);
  830. auto prototype_or_error = object.internal_get_prototype_of();
  831. if (prototype_or_error.has_value() && prototype_or_error.value() != nullptr) {
  832. auto& prototype = *prototype_or_error.value();
  833. if (&prototype == prototype.shape().realm().intrinsics().error_prototype())
  834. return print_error(print_context, object, seen_objects);
  835. }
  836. if (is<JS::RegExpObject>(object))
  837. return print_regexp_object(print_context, static_cast<JS::RegExpObject&>(object), seen_objects);
  838. if (is<JS::Map>(object))
  839. return print_map(print_context, static_cast<JS::Map&>(object), seen_objects);
  840. if (is<JS::Set>(object))
  841. return print_set(print_context, static_cast<JS::Set&>(object), seen_objects);
  842. if (is<JS::WeakMap>(object))
  843. return print_weak_map(print_context, static_cast<JS::WeakMap&>(object), seen_objects);
  844. if (is<JS::WeakSet>(object))
  845. return print_weak_set(print_context, static_cast<JS::WeakSet&>(object), seen_objects);
  846. if (is<JS::WeakRef>(object))
  847. return print_weak_ref(print_context, static_cast<JS::WeakRef&>(object), seen_objects);
  848. if (is<JS::DataView>(object))
  849. return print_data_view(print_context, static_cast<JS::DataView&>(object), seen_objects);
  850. if (is<JS::ProxyObject>(object))
  851. return print_proxy_object(print_context, static_cast<JS::ProxyObject&>(object), seen_objects);
  852. if (is<JS::Promise>(object))
  853. return print_promise(print_context, static_cast<JS::Promise&>(object), seen_objects);
  854. if (is<JS::ArrayBuffer>(object))
  855. return print_array_buffer(print_context, static_cast<JS::ArrayBuffer&>(object), seen_objects);
  856. if (is<JS::ShadowRealm>(object))
  857. return print_shadow_realm(print_context, static_cast<JS::ShadowRealm&>(object), seen_objects);
  858. if (is<JS::GeneratorObject>(object))
  859. return print_generator(print_context, static_cast<JS::GeneratorObject&>(object), seen_objects);
  860. if (is<JS::AsyncGenerator>(object))
  861. return print_async_generator(print_context, static_cast<JS::AsyncGenerator&>(object), seen_objects);
  862. if (object.is_typed_array())
  863. return print_typed_array(print_context, static_cast<JS::TypedArrayBase&>(object), seen_objects);
  864. if (is<JS::BooleanObject>(object))
  865. return print_boolean_object(print_context, static_cast<JS::BooleanObject&>(object), seen_objects);
  866. if (is<JS::NumberObject>(object))
  867. return print_number_object(print_context, static_cast<JS::NumberObject&>(object), seen_objects);
  868. if (is<JS::StringObject>(object))
  869. return print_string_object(print_context, static_cast<JS::StringObject&>(object), seen_objects);
  870. if (is<JS::Intl::DisplayNames>(object))
  871. return print_intl_display_names(print_context, static_cast<JS::Intl::DisplayNames&>(object), seen_objects);
  872. if (is<JS::Intl::Locale>(object))
  873. return print_intl_locale(print_context, static_cast<JS::Intl::Locale&>(object), seen_objects);
  874. if (is<JS::Intl::ListFormat>(object))
  875. return print_intl_list_format(print_context, static_cast<JS::Intl::ListFormat&>(object), seen_objects);
  876. if (is<JS::Intl::NumberFormat>(object))
  877. return print_intl_number_format(print_context, static_cast<JS::Intl::NumberFormat&>(object), seen_objects);
  878. if (is<JS::Intl::DateTimeFormat>(object))
  879. return print_intl_date_time_format(print_context, static_cast<JS::Intl::DateTimeFormat&>(object), seen_objects);
  880. if (is<JS::Intl::RelativeTimeFormat>(object))
  881. return print_intl_relative_time_format(print_context, static_cast<JS::Intl::RelativeTimeFormat&>(object), seen_objects);
  882. if (is<JS::Intl::PluralRules>(object))
  883. return print_intl_plural_rules(print_context, static_cast<JS::Intl::PluralRules&>(object), seen_objects);
  884. if (is<JS::Intl::Collator>(object))
  885. return print_intl_collator(print_context, static_cast<JS::Intl::Collator&>(object), seen_objects);
  886. if (is<JS::Intl::Segmenter>(object))
  887. return print_intl_segmenter(print_context, static_cast<JS::Intl::Segmenter&>(object), seen_objects);
  888. if (is<JS::Intl::Segments>(object))
  889. return print_intl_segments(print_context, static_cast<JS::Intl::Segments&>(object), seen_objects);
  890. if (is<JS::Intl::DurationFormat>(object))
  891. return print_intl_duration_format(print_context, static_cast<JS::Intl::DurationFormat&>(object), seen_objects);
  892. if (is<JS::Temporal::Duration>(object))
  893. return print_temporal_duration(print_context, static_cast<JS::Temporal::Duration&>(object), seen_objects);
  894. if (is<JS::Temporal::PlainMonthDay>(object))
  895. return print_temporal_plain_month_day(print_context, static_cast<JS::Temporal::PlainMonthDay&>(object), seen_objects);
  896. if (is<JS::Temporal::PlainYearMonth>(object))
  897. return print_temporal_plain_year_month(print_context, static_cast<JS::Temporal::PlainYearMonth&>(object), seen_objects);
  898. return print_object(print_context, object, seen_objects);
  899. }
  900. if (value.is_string())
  901. TRY(js_out(print_context, "\033[32;1m"));
  902. else if (value.is_number() || value.is_bigint())
  903. TRY(js_out(print_context, "\033[35;1m"));
  904. else if (value.is_boolean())
  905. TRY(js_out(print_context, "\033[33;1m"));
  906. else if (value.is_null())
  907. TRY(js_out(print_context, "\033[33;1m"));
  908. else if (value.is_undefined())
  909. TRY(js_out(print_context, "\033[34;1m"));
  910. if (value.is_string())
  911. TRY(js_out(print_context, "\""));
  912. else if (value.is_negative_zero())
  913. TRY(js_out(print_context, "-"));
  914. auto contents = value.to_string_without_side_effects();
  915. if (value.is_string())
  916. TRY(js_out(print_context, "{}", TRY(escape_for_string_literal(contents))));
  917. else
  918. TRY(js_out(print_context, "{}", contents));
  919. if (value.is_string())
  920. TRY(js_out(print_context, "\""));
  921. TRY(js_out(print_context, "\033[0m"));
  922. return {};
  923. }
  924. }
  925. namespace JS {
  926. ErrorOr<void> print(JS::Value value, PrintContext& print_context)
  927. {
  928. HashTable<JS::Object*> seen_objects;
  929. return print_value(print_context, value, seen_objects);
  930. }
  931. }