1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-13 22:17:36 +00:00

js: Convert JavaScript REPL to ThrowCompletionOr

This commit is contained in:
Timothy Flynn 2021-10-29 17:13:18 -04:00 committed by Idan Horowitz
parent e8f722fb27
commit 0f91b22795

View file

@ -77,11 +77,11 @@ public:
virtual ~ReplObject() override = default; virtual ~ReplObject() override = default;
private: private:
JS_DECLARE_OLD_NATIVE_FUNCTION(exit_interpreter); JS_DECLARE_NATIVE_FUNCTION(exit_interpreter);
JS_DECLARE_OLD_NATIVE_FUNCTION(repl_help); JS_DECLARE_NATIVE_FUNCTION(repl_help);
JS_DECLARE_OLD_NATIVE_FUNCTION(load_file); JS_DECLARE_NATIVE_FUNCTION(load_file);
JS_DECLARE_OLD_NATIVE_FUNCTION(save_to_file); JS_DECLARE_NATIVE_FUNCTION(save_to_file);
JS_DECLARE_OLD_NATIVE_FUNCTION(load_json); JS_DECLARE_NATIVE_FUNCTION(load_json);
}; };
class ScriptObject final : public JS::GlobalObject { class ScriptObject final : public JS::GlobalObject {
@ -93,8 +93,8 @@ public:
virtual ~ScriptObject() override = default; virtual ~ScriptObject() override = default;
private: private:
JS_DECLARE_OLD_NATIVE_FUNCTION(load_file); JS_DECLARE_NATIVE_FUNCTION(load_file);
JS_DECLARE_OLD_NATIVE_FUNCTION(load_json); JS_DECLARE_NATIVE_FUNCTION(load_json);
}; };
static bool s_dump_ast = false; static bool s_dump_ast = false;
@ -891,42 +891,35 @@ static bool parse_and_run(JS::Interpreter& interpreter, StringView source, Strin
return true; return true;
} }
static JS::Value load_file_impl(JS::VM& vm, JS::GlobalObject& global_object) static JS::ThrowCompletionOr<JS::Value> load_file_impl(JS::VM& vm, JS::GlobalObject& global_object)
{ {
auto filename = TRY_OR_DISCARD(vm.argument(0).to_string(global_object)); auto filename = TRY(vm.argument(0).to_string(global_object));
auto file = Core::File::construct(filename); auto file = Core::File::construct(filename);
if (!file->open(Core::OpenMode::ReadOnly)) { if (!file->open(Core::OpenMode::ReadOnly))
vm.throw_exception<JS::Error>(global_object, String::formatted("Failed to open '{}': {}", filename, file->error_string())); return vm.throw_completion<JS::Error>(global_object, String::formatted("Failed to open '{}': {}", filename, file->error_string()));
return {};
}
auto file_contents = file->read_all(); auto file_contents = file->read_all();
auto source = StringView { file_contents }; auto source = StringView { file_contents };
auto parser = JS::Parser(JS::Lexer(source)); auto parser = JS::Parser(JS::Lexer(source));
auto program = parser.parse_program(); auto program = parser.parse_program();
if (parser.has_errors()) { if (parser.has_errors()) {
auto& error = parser.errors()[0]; auto& error = parser.errors()[0];
vm.throw_exception<JS::SyntaxError>(global_object, error.to_string()); return vm.throw_completion<JS::SyntaxError>(global_object, error.to_string());
return {};
} }
// FIXME: Use eval()-like semantics and execute in current scope? // FIXME: Use eval()-like semantics and execute in current scope?
vm.interpreter().run(global_object, *program); vm.interpreter().run(global_object, *program);
return JS::js_undefined(); return JS::js_undefined();
} }
static JS::Value load_json_impl(JS::VM& vm, JS::GlobalObject& global_object) static JS::ThrowCompletionOr<JS::Value> load_json_impl(JS::VM& vm, JS::GlobalObject& global_object)
{ {
auto filename = TRY_OR_DISCARD(vm.argument(0).to_string(global_object)); auto filename = TRY(vm.argument(0).to_string(global_object));
auto file = Core::File::construct(filename); auto file = Core::File::construct(filename);
if (!file->open(Core::OpenMode::ReadOnly)) { if (!file->open(Core::OpenMode::ReadOnly))
vm.throw_exception<JS::Error>(global_object, String::formatted("Failed to open '{}': {}", filename, file->error_string())); return vm.throw_completion<JS::Error>(global_object, String::formatted("Failed to open '{}': {}", filename, file->error_string()));
return {};
}
auto file_contents = file->read_all(); auto file_contents = file->read_all();
auto json = JsonValue::from_string(file_contents); auto json = JsonValue::from_string(file_contents);
if (!json.has_value()) { if (!json.has_value())
vm.throw_exception<JS::SyntaxError>(global_object, JS::ErrorType::JsonMalformed); return vm.throw_completion<JS::SyntaxError>(global_object, JS::ErrorType::JsonMalformed);
return {};
}
return JS::JSONObject::parse_json_value(global_object, json.value()); return JS::JSONObject::parse_json_value(global_object, json.value());
} }
@ -935,14 +928,14 @@ void ReplObject::initialize_global_object()
Base::initialize_global_object(); Base::initialize_global_object();
define_direct_property("global", this, JS::Attribute::Enumerable); define_direct_property("global", this, JS::Attribute::Enumerable);
u8 attr = JS::Attribute::Configurable | JS::Attribute::Writable | JS::Attribute::Enumerable; u8 attr = JS::Attribute::Configurable | JS::Attribute::Writable | JS::Attribute::Enumerable;
define_old_native_function("exit", exit_interpreter, 0, attr); define_native_function("exit", exit_interpreter, 0, attr);
define_old_native_function("help", repl_help, 0, attr); define_native_function("help", repl_help, 0, attr);
define_old_native_function("load", load_file, 1, attr); define_native_function("load", load_file, 1, attr);
define_old_native_function("save", save_to_file, 1, attr); define_native_function("save", save_to_file, 1, attr);
define_old_native_function("loadJSON", load_json, 1, attr); define_native_function("loadJSON", load_json, 1, attr);
} }
JS_DEFINE_OLD_NATIVE_FUNCTION(ReplObject::save_to_file) JS_DEFINE_NATIVE_FUNCTION(ReplObject::save_to_file)
{ {
if (!vm.argument_count()) if (!vm.argument_count())
return JS::Value(false); return JS::Value(false);
@ -954,14 +947,14 @@ JS_DEFINE_OLD_NATIVE_FUNCTION(ReplObject::save_to_file)
return JS::Value(false); return JS::Value(false);
} }
JS_DEFINE_OLD_NATIVE_FUNCTION(ReplObject::exit_interpreter) JS_DEFINE_NATIVE_FUNCTION(ReplObject::exit_interpreter)
{ {
if (!vm.argument_count()) if (!vm.argument_count())
exit(0); exit(0);
exit(TRY_OR_DISCARD(vm.argument(0).to_number(global_object)).as_double()); exit(TRY(vm.argument(0).to_number(global_object)).as_double());
} }
JS_DEFINE_OLD_NATIVE_FUNCTION(ReplObject::repl_help) JS_DEFINE_NATIVE_FUNCTION(ReplObject::repl_help)
{ {
outln("REPL commands:"); outln("REPL commands:");
outln(" exit(code): exit the REPL with specified code. Defaults to 0."); outln(" exit(code): exit the REPL with specified code. Defaults to 0.");
@ -971,12 +964,12 @@ JS_DEFINE_OLD_NATIVE_FUNCTION(ReplObject::repl_help)
return JS::js_undefined(); return JS::js_undefined();
} }
JS_DEFINE_OLD_NATIVE_FUNCTION(ReplObject::load_file) JS_DEFINE_NATIVE_FUNCTION(ReplObject::load_file)
{ {
return load_file_impl(vm, global_object); return load_file_impl(vm, global_object);
} }
JS_DEFINE_OLD_NATIVE_FUNCTION(ReplObject::load_json) JS_DEFINE_NATIVE_FUNCTION(ReplObject::load_json)
{ {
return load_json_impl(vm, global_object); return load_json_impl(vm, global_object);
} }
@ -986,16 +979,16 @@ void ScriptObject::initialize_global_object()
Base::initialize_global_object(); Base::initialize_global_object();
define_direct_property("global", this, JS::Attribute::Enumerable); define_direct_property("global", this, JS::Attribute::Enumerable);
u8 attr = JS::Attribute::Configurable | JS::Attribute::Writable | JS::Attribute::Enumerable; u8 attr = JS::Attribute::Configurable | JS::Attribute::Writable | JS::Attribute::Enumerable;
define_old_native_function("load", load_file, 1, attr); define_native_function("load", load_file, 1, attr);
define_old_native_function("loadJSON", load_json, 1, attr); define_native_function("loadJSON", load_json, 1, attr);
} }
JS_DEFINE_OLD_NATIVE_FUNCTION(ScriptObject::load_file) JS_DEFINE_NATIVE_FUNCTION(ScriptObject::load_file)
{ {
return load_file_impl(vm, global_object); return load_file_impl(vm, global_object);
} }
JS_DEFINE_OLD_NATIVE_FUNCTION(ScriptObject::load_json) JS_DEFINE_NATIVE_FUNCTION(ScriptObject::load_json)
{ {
return load_json_impl(vm, global_object); return load_json_impl(vm, global_object);
} }