mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 14:57:35 +00:00
js: Consolidate and re-implement the load() function
This replaces the two sloppy copies of the load() function with a cleaned up implementation: - Only use the first argument, to load multiple files just call the function multiple times - Fix a crash when using any non-string argument - Throw an error if the file can't be opened instead of logging to stderr - Don't use parse_and_run(), which would print the AST of the loaded file when using -A, for example - it's used either way as the entry point in both REPL and non-REPL mode, so we already get exception handling and all that
This commit is contained in:
parent
64f4dc9a36
commit
bdd7741ae1
1 changed files with 30 additions and 44 deletions
|
@ -544,6 +544,32 @@ static bool parse_and_run(JS::Interpreter& interpreter, const StringView& source
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static JS::Value load_file_impl(JS::VM& vm, JS::GlobalObject& global_object)
|
||||||
|
{
|
||||||
|
auto filename = vm.argument(0).to_string(global_object);
|
||||||
|
if (vm.exception())
|
||||||
|
return {};
|
||||||
|
auto file = Core::File::construct(filename);
|
||||||
|
if (!file->open(Core::OpenMode::ReadOnly)) {
|
||||||
|
vm.throw_exception<JS::Error>(global_object, String::formatted("Failed to open '{}': {}", filename, file->error_string()));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
auto file_contents = file->read_all();
|
||||||
|
auto source = file_has_shebang(file_contents)
|
||||||
|
? strip_shebang(file_contents)
|
||||||
|
: StringView { file_contents };
|
||||||
|
auto parser = JS::Parser(JS::Lexer(source));
|
||||||
|
auto program = parser.parse_program();
|
||||||
|
if (parser.has_errors()) {
|
||||||
|
auto& error = parser.errors()[0];
|
||||||
|
vm.throw_exception<JS::SyntaxError>(global_object, error.to_string());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
// FIXME: Use eval()-like semantics and execute in current scope?
|
||||||
|
vm.interpreter().run(global_object, *program);
|
||||||
|
return JS::js_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
void ReplObject::initialize_global_object()
|
void ReplObject::initialize_global_object()
|
||||||
{
|
{
|
||||||
Base::initialize_global_object();
|
Base::initialize_global_object();
|
||||||
|
@ -581,34 +607,14 @@ 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.");
|
||||||
outln(" help(): display this menu");
|
outln(" help(): display this menu");
|
||||||
outln(" load(files): accepts filenames as params to load into running session. For example load(\"js/1.js\", \"js/2.js\", \"js/3.js\")");
|
outln(" load(file): load given JS file into running session. For example: load(\"foo.js\")");
|
||||||
outln(" save(file): accepts a filename, writes REPL input history to a file. For example: save(\"foo.txt\")");
|
outln(" save(file): write REPL input history to the given file. For example: save(\"foo.txt\")");
|
||||||
return JS::js_undefined();
|
return JS::js_undefined();
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_DEFINE_NATIVE_FUNCTION(ReplObject::load_file)
|
JS_DEFINE_NATIVE_FUNCTION(ReplObject::load_file)
|
||||||
{
|
{
|
||||||
if (!vm.argument_count())
|
return load_file_impl(vm, global_object);
|
||||||
return JS::Value(false);
|
|
||||||
|
|
||||||
for (auto& file : vm.call_frame().arguments) {
|
|
||||||
String filename = file.as_string().string();
|
|
||||||
auto js_file = Core::File::construct(filename);
|
|
||||||
if (!js_file->open(Core::OpenMode::ReadOnly)) {
|
|
||||||
warnln("Failed to open {}: {}", filename, js_file->error_string());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
auto file_contents = js_file->read_all();
|
|
||||||
|
|
||||||
StringView source;
|
|
||||||
if (file_has_shebang(file_contents)) {
|
|
||||||
source = strip_shebang(file_contents);
|
|
||||||
} else {
|
|
||||||
source = file_contents;
|
|
||||||
}
|
|
||||||
parse_and_run(vm.interpreter(), source);
|
|
||||||
}
|
|
||||||
return JS::Value(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptObject::initialize_global_object()
|
void ScriptObject::initialize_global_object()
|
||||||
|
@ -620,27 +626,7 @@ void ScriptObject::initialize_global_object()
|
||||||
|
|
||||||
JS_DEFINE_NATIVE_FUNCTION(ScriptObject::load_file)
|
JS_DEFINE_NATIVE_FUNCTION(ScriptObject::load_file)
|
||||||
{
|
{
|
||||||
if (!vm.argument_count())
|
return load_file_impl(vm, global_object);
|
||||||
return JS::Value(false);
|
|
||||||
|
|
||||||
for (auto& file : vm.call_frame().arguments) {
|
|
||||||
String filename = file.as_string().string();
|
|
||||||
auto js_file = Core::File::construct(filename);
|
|
||||||
if (!js_file->open(Core::OpenMode::ReadOnly)) {
|
|
||||||
warnln("Failed to open {}: {}", filename, js_file->error_string());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
auto file_contents = js_file->read_all();
|
|
||||||
|
|
||||||
StringView source;
|
|
||||||
if (file_has_shebang(file_contents)) {
|
|
||||||
source = strip_shebang(file_contents);
|
|
||||||
} else {
|
|
||||||
source = file_contents;
|
|
||||||
}
|
|
||||||
parse_and_run(vm.interpreter(), source);
|
|
||||||
}
|
|
||||||
return JS::Value(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void repl(JS::Interpreter& interpreter)
|
static void repl(JS::Interpreter& interpreter)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue