js: Use new string formatting functions

This commit is contained in:
Linus Groh 2020-11-09 19:10:59 +00:00 committed by Andreas Kling
parent 626c17d284
commit 518481086b
Notes: sideshowbarker 2024-07-19 01:28:05 +09:00

View file

@ -25,6 +25,7 @@
*/
#include <AK/ByteBuffer.h>
#include <AK/Format.h>
#include <AK/NonnullOwnPtr.h>
#include <AK/StringBuilder.h>
#include <LibCore/ArgsParser.h>
@ -161,10 +162,10 @@ static void print_value(JS::Value value, HashTable<JS::Object*>& seen_objects);
static void print_array(JS::Array& array, HashTable<JS::Object*>& seen_objects)
{
bool first = true;
fputs("[ ", stdout);
out("[ ");
for (auto it = array.indexed_properties().begin(false); it != array.indexed_properties().end(); ++it) {
if (!first)
fputs(", ", stdout);
out(", ");
first = false;
auto value = it.value_and_attributes(&array).value;
// The V8 repl doesn't throw an exception here, and instead just
@ -174,18 +175,18 @@ static void print_array(JS::Array& array, HashTable<JS::Object*>& seen_objects)
return;
print_value(value, seen_objects);
}
fputs(" ]", stdout);
out(" ]");
}
static void print_object(JS::Object& object, HashTable<JS::Object*>& seen_objects)
{
fputs("{ ", stdout);
out("{{ ");
bool first = true;
for (auto& entry : object.indexed_properties()) {
if (!first)
fputs(", ", stdout);
out(", ");
first = false;
printf("\"\033[33;1m%d\033[0m\": ", entry.index());
out("\"\033[33;1m{}\033[0m\": ", entry.index());
auto value = entry.value_and_attributes(&object).value;
// The V8 repl doesn't throw an exception here, and instead just
// prints 'undefined'. We may choose to replicate that behavior in
@ -196,51 +197,51 @@ static void print_object(JS::Object& object, HashTable<JS::Object*>& seen_object
}
if (!object.indexed_properties().is_empty() && object.shape().property_count())
fputs(", ", stdout);
out(", ");
size_t index = 0;
for (auto& it : object.shape().property_table_ordered()) {
if (it.key.is_string()) {
printf("\"\033[33;1m%s\033[0m\": ", it.key.to_display_string().characters());
out("\"\033[33;1m{}\033[0m\": ", it.key.to_display_string());
} else {
printf("\033[33;1m%s\033[0m: ", it.key.to_display_string().characters());
out("\033[33;1m{}\033[0m: ", it.key.to_display_string());
}
print_value(object.get_direct(it.value.offset), seen_objects);
if (index != object.shape().property_count() - 1)
fputs(", ", stdout);
out(", ");
++index;
}
fputs(" }", stdout);
out(" }}");
}
static void print_function(const JS::Object& function, HashTable<JS::Object*>&)
{
printf("\033[34;1m[%s]\033[0m", function.class_name());
out("\033[34;1m[{}]\033[0m", function.class_name());
}
static void print_date(const JS::Object& date, HashTable<JS::Object*>&)
{
printf("\033[34;1mDate %s\033[0m", static_cast<const JS::Date&>(date).string().characters());
out("\033[34;1mDate {}\033[0m", static_cast<const JS::Date&>(date).string());
}
static void print_error(const JS::Object& object, HashTable<JS::Object*>&)
{
auto& error = static_cast<const JS::Error&>(object);
printf("\033[34;1m[%s]\033[0m", error.name().characters());
out("\033[34;1m[{}]\033[0m", error.name());
if (!error.message().is_empty())
printf(": %s", error.message().characters());
out(": {}", error.message());
}
static void print_regexp(const JS::Object& object, HashTable<JS::Object*>&)
{
auto& regexp = static_cast<const JS::RegExpObject&>(object);
printf("\033[34;1m/%s/%s\033[0m", regexp.content().characters(), regexp.flags().characters());
out("\033[34;1m/{}/{}\033[0m", regexp.content(), regexp.flags());
}
static void print_value(JS::Value value, HashTable<JS::Object*>& seen_objects)
{
if (value.is_empty()) {
printf("\033[34;1m<empty>\033[0m");
out("\033[34;1m<empty>\033[0m");
return;
}
@ -248,7 +249,7 @@ static void print_value(JS::Value value, HashTable<JS::Object*>& seen_objects)
if (seen_objects.contains(&value.as_object())) {
// FIXME: Maybe we should only do this for circular references,
// not for all reoccurring objects.
printf("<already printed Object %p>", &value.as_object());
out("<already printed Object {}>", &value.as_object());
return;
}
seen_objects.set(&value.as_object());
@ -271,30 +272,30 @@ static void print_value(JS::Value value, HashTable<JS::Object*>& seen_objects)
}
if (value.is_string())
printf("\033[32;1m");
out("\033[32;1m");
else if (value.is_number() || value.is_bigint())
printf("\033[35;1m");
out("\033[35;1m");
else if (value.is_boolean())
printf("\033[33;1m");
out("\033[33;1m");
else if (value.is_null())
printf("\033[33;1m");
out("\033[33;1m");
else if (value.is_undefined())
printf("\033[34;1m");
out("\033[34;1m");
if (value.is_string())
putchar('"');
out("\"");
else if (value.is_negative_zero())
putchar('-');
printf("%s", value.to_string_without_side_effects().characters());
out("-");
out("{}", value.to_string_without_side_effects());
if (value.is_string())
putchar('"');
printf("\033[0m");
out("\"");
out("\033[0m");
}
static void print(JS::Value value)
{
HashTable<JS::Object*> seen_objects;
print_value(value, seen_objects);
putchar('\n');
outln();
}
static bool file_has_shebang(AK::ByteBuffer file_contents)
@ -352,14 +353,14 @@ static bool parse_and_run(JS::Interpreter& interpreter, const StringView& source
auto error = parser.errors()[0];
auto hint = error.source_location_hint(source);
if (!hint.is_empty())
printf("%s\n", hint.characters());
outln("{}", hint);
vm->throw_exception<JS::SyntaxError>(interpreter.global_object(), error.to_string());
} else {
interpreter.run(interpreter.global_object(), *program);
}
if (vm->exception()) {
printf("Uncaught exception: ");
out("Uncaught exception: ");
print(vm->exception()->value());
auto trace = vm->exception()->trace();
if (trace.size() > 1) {
@ -433,11 +434,11 @@ JS_DEFINE_NATIVE_FUNCTION(ReplObject::exit_interpreter)
JS_DEFINE_NATIVE_FUNCTION(ReplObject::repl_help)
{
printf("REPL commands:\n");
printf(" exit(code): exit the REPL with specified code. Defaults to 0.\n");
printf(" help(): display this menu\n");
printf(" load(files): accepts file names as params to load into running session. For example load(\"js/1.js\", \"js/2.js\", \"js/3.js\")\n");
printf(" save(file): accepts a file name, writes REPL input history to a file. For example: save(\"foo.txt\")\n");
outln("REPL commands:");
outln(" exit(code): exit the REPL with specified code. Defaults to 0.");
outln(" help(): display this menu");
outln(" load(files): accepts file names as params to load into running session. For example load(\"js/1.js\", \"js/2.js\", \"js/3.js\")");
outln(" save(file): accepts a file name, writes REPL input history to a file. For example: save(\"foo.txt\")");
return JS::js_undefined();
}
@ -450,7 +451,8 @@ JS_DEFINE_NATIVE_FUNCTION(ReplObject::load_file)
String file_name = file.as_string().string();
auto js_file = Core::File::construct(file_name);
if (!js_file->open(Core::IODevice::ReadOnly)) {
fprintf(stderr, "Failed to open %s: %s\n", file_name.characters(), js_file->error_string());
warnln("Failed to open {}: {}", file_name, js_file->error_string());
continue;
}
auto file_contents = js_file->read_all();
@ -491,49 +493,43 @@ public:
virtual JS::Value log() override
{
puts(vm().join_arguments().characters());
outln("{}", vm().join_arguments());
return JS::js_undefined();
}
virtual JS::Value info() override
{
printf("(i) %s\n", vm().join_arguments().characters());
outln("(i) {}", vm().join_arguments());
return JS::js_undefined();
}
virtual JS::Value debug() override
{
printf("\033[36;1m");
puts(vm().join_arguments().characters());
printf("\033[0m");
outln("\033[36;1m{}\033[0m", vm().join_arguments());
return JS::js_undefined();
}
virtual JS::Value warn() override
{
printf("\033[33;1m");
puts(vm().join_arguments().characters());
printf("\033[0m");
outln("\033[33;1m{}\033[0m", vm().join_arguments());
return JS::js_undefined();
}
virtual JS::Value error() override
{
printf("\033[31;1m");
puts(vm().join_arguments().characters());
printf("\033[0m");
outln("\033[31;1m{}\033[0m", vm().join_arguments());
return JS::js_undefined();
}
virtual JS::Value clear() override
{
printf("\033[3J\033[H\033[2J");
out("\033[3J\033[H\033[2J");
fflush(stdout);
return JS::js_undefined();
}
virtual JS::Value trace() override
{
puts(vm().join_arguments().characters());
outln("{}", vm().join_arguments());
auto trace = get_trace();
for (auto& function_name : trace) {
if (function_name.is_empty())
function_name = "<anonymous>";
printf(" -> %s\n", function_name.characters());
outln(" -> {}", function_name);
}
return JS::js_undefined();
}
@ -541,19 +537,16 @@ public:
{
auto label = vm().argument_count() ? vm().argument(0).to_string_without_side_effects() : "default";
auto counter_value = m_console.counter_increment(label);
printf("%s: %u\n", label.characters(), counter_value);
outln("{}: {}", label, counter_value);
return JS::js_undefined();
}
virtual JS::Value count_reset() override
{
auto label = vm().argument_count() ? vm().argument(0).to_string_without_side_effects() : "default";
if (m_console.counter_reset(label)) {
printf("%s: 0\n", label.characters());
} else {
printf("\033[33;1m");
printf("\"%s\" doesn't have a count\n", label.characters());
printf("\033[0m");
}
if (m_console.counter_reset(label))
outln("{}: 0", label);
else
outln("\033[33;1m\"{}\" doesn't have a count\033[0m", label);
return JS::js_undefined();
}
};
@ -797,7 +790,7 @@ int main(int argc, char** argv)
auto file = Core::File::construct(script_path);
if (!file->open(Core::IODevice::ReadOnly)) {
fprintf(stderr, "Failed to open %s: %s\n", script_path, file->error_string());
warnln("Failed to open {}: {}", script_path, file->error_string());
return 1;
}
auto file_contents = file->read_all();