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