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