Browse Source

LibJS+LibTest: Use JS::Script and JS::SourceTextModule in test-js

Instead of creating a Parser and Lexer manually in test-js, we now
use either JS::Script::parse() or JS::SourceTextModule::parse()
to load tests.
Andreas Kling 3 years ago
parent
commit
0a09eaf3a1
2 changed files with 49 additions and 29 deletions
  1. 8 4
      Tests/LibJS/test-js.cpp
  2. 41 25
      Userland/Libraries/LibTest/JavaScriptTestRunner.h

+ 8 - 4
Tests/LibJS/test-js.cpp

@@ -94,7 +94,7 @@ TESTJS_GLOBAL_FUNCTION(mark_as_garbage, markAsGarbage)
     return JS::js_undefined();
     return JS::js_undefined();
 }
 }
 
 
-TESTJS_RUN_FILE_FUNCTION(const String& test_file, JS::Interpreter&)
+TESTJS_RUN_FILE_FUNCTION(String const& test_file, JS::Interpreter& interpreter)
 {
 {
     if (!test262_parser_tests)
     if (!test262_parser_tests)
         return Test::JS::RunFileHookResult::RunAsNormal;
         return Test::JS::RunFileHookResult::RunAsNormal;
@@ -122,8 +122,12 @@ TESTJS_RUN_FILE_FUNCTION(const String& test_file, JS::Interpreter&)
         return Test::JS::RunFileHookResult::SkipFile;
         return Test::JS::RunFileHookResult::SkipFile;
 
 
     auto program_type = path.basename().ends_with(".module.js") ? JS::Program::Type::Module : JS::Program::Type::Script;
     auto program_type = path.basename().ends_with(".module.js") ? JS::Program::Type::Module : JS::Program::Type::Script;
+    bool parse_succeeded = false;
+    if (program_type == JS::Program::Type::Module)
+        parse_succeeded = !Test::JS::parse_module(test_file, interpreter.realm()).is_error();
+    else
+        parse_succeeded = !Test::JS::parse_script(test_file, interpreter.realm()).is_error();
 
 
-    auto parse_result = Test::JS::parse_file(test_file, program_type);
     bool test_passed = true;
     bool test_passed = true;
     String message;
     String message;
     String expectation_string;
     String expectation_string;
@@ -132,14 +136,14 @@ TESTJS_RUN_FILE_FUNCTION(const String& test_file, JS::Interpreter&)
     case Early:
     case Early:
     case Fail:
     case Fail:
         expectation_string = "File should not parse";
         expectation_string = "File should not parse";
-        test_passed = parse_result.is_error();
+        test_passed = !parse_succeeded;
         if (!test_passed)
         if (!test_passed)
             message = "Expected the file to fail parsing, but it did not";
             message = "Expected the file to fail parsing, but it did not";
         break;
         break;
     case Pass:
     case Pass:
     case ExplicitPass:
     case ExplicitPass:
         expectation_string = "File should parse";
         expectation_string = "File should parse";
-        test_passed = !parse_result.is_error();
+        test_passed = parse_succeeded;
         if (!test_passed)
         if (!test_passed)
             message = "Expected the file to parse, but it did not";
             message = "Expected the file to parse, but it did not";
         break;
         break;

+ 41 - 25
Userland/Libraries/LibTest/JavaScriptTestRunner.h

@@ -29,6 +29,8 @@
 #include <LibJS/Runtime/TypedArray.h>
 #include <LibJS/Runtime/TypedArray.h>
 #include <LibJS/Runtime/WeakMap.h>
 #include <LibJS/Runtime/WeakMap.h>
 #include <LibJS/Runtime/WeakSet.h>
 #include <LibJS/Runtime/WeakSet.h>
+#include <LibJS/Script.h>
+#include <LibJS/SourceTextModule.h>
 #include <LibTest/Results.h>
 #include <LibTest/Results.h>
 #include <LibTest/TestRunner.h>
 #include <LibTest/TestRunner.h>
 #include <fcntl.h>
 #include <fcntl.h>
@@ -169,7 +171,7 @@ protected:
     void print_file_result(const JSFileResult& file_result) const;
     void print_file_result(const JSFileResult& file_result) const;
 
 
     String m_common_path;
     String m_common_path;
-    RefPtr<JS::Program> m_test_program;
+    RefPtr<JS::Script> m_test_script;
 };
 };
 
 
 class TestRunnerGlobalObject final : public JS::GlobalObject {
 class TestRunnerGlobalObject final : public JS::GlobalObject {
@@ -195,28 +197,42 @@ inline void TestRunnerGlobalObject::initialize_global_object()
     }
     }
 }
 }
 
 
-inline AK::Result<NonnullRefPtr<JS::Program>, ParserError> parse_file(const String& file_path, JS::Program::Type program_type = JS::Program::Type::Script)
+inline ByteBuffer load_entire_file(StringView path)
 {
 {
-    auto file = Core::File::construct(file_path);
-    auto result = file->open(Core::OpenMode::ReadOnly);
-    if (!result) {
-        warnln("Failed to open the following file: \"{}\"", file_path);
+    auto file_or_error = Core::File::open(path, Core::OpenMode::ReadOnly);
+    if (file_or_error.is_error()) {
+        warnln("Failed to open the following file: \"{}\"", path);
         cleanup_and_exit();
         cleanup_and_exit();
     }
     }
 
 
-    auto contents = file->read_all();
-    String test_file_string(reinterpret_cast<const char*>(contents.data()), contents.size());
-    file->close();
+    auto file = file_or_error.release_value();
+    return file->read_all();
+}
+
+inline AK::Result<NonnullRefPtr<JS::Script>, ParserError> parse_script(StringView path, JS::Realm& realm)
+{
+    auto contents = load_entire_file(path);
+    auto script_or_errors = JS::Script::parse(contents, realm, path);
+
+    if (script_or_errors.is_error()) {
+        auto errors = script_or_errors.release_error();
+        return ParserError { errors[0], errors[0].source_location_hint(contents) };
+    }
+
+    return script_or_errors.release_value();
+}
 
 
-    auto parser = JS::Parser(JS::Lexer(test_file_string), program_type);
-    auto program = parser.parse_program();
+inline AK::Result<NonnullRefPtr<JS::SourceTextModule>, ParserError> parse_module(StringView path, JS::Realm& realm)
+{
+    auto contents = load_entire_file(path);
+    auto script_or_errors = JS::SourceTextModule::parse(contents, realm, path);
 
 
-    if (parser.has_errors()) {
-        auto error = parser.errors()[0];
-        return AK::Result<NonnullRefPtr<JS::Program>, ParserError>(ParserError { error, error.source_location_hint(test_file_string) });
+    if (script_or_errors.is_error()) {
+        auto errors = script_or_errors.release_error();
+        return ParserError { errors[0], errors[0].source_location_hint(contents) };
     }
     }
 
 
-    return AK::Result<NonnullRefPtr<JS::Program>, ParserError>(program);
+    return script_or_errors.release_value();
 }
 }
 
 
 inline Optional<JsonValue> get_test_results(JS::Interpreter& interpreter)
 inline Optional<JsonValue> get_test_results(JS::Interpreter& interpreter)
@@ -304,19 +320,19 @@ inline JSFileResult TestRunner::run_file_test(const String& test_path)
         }
         }
     }
     }
 
 
-    if (!m_test_program) {
-        auto result = parse_file(m_common_path);
+    if (!m_test_script) {
+        auto result = parse_script(m_common_path, interpreter->realm());
         if (result.is_error()) {
         if (result.is_error()) {
             warnln("Unable to parse test-common.js");
             warnln("Unable to parse test-common.js");
             warnln("{}", result.error().error.to_string());
             warnln("{}", result.error().error.to_string());
             warnln("{}", result.error().hint);
             warnln("{}", result.error().hint);
             cleanup_and_exit();
             cleanup_and_exit();
         }
         }
-        m_test_program = result.value();
+        m_test_script = result.release_value();
     }
     }
 
 
     if (g_run_bytecode) {
     if (g_run_bytecode) {
-        auto unit = JS::Bytecode::Generator::generate(*m_test_program);
+        auto unit = JS::Bytecode::Generator::generate(m_test_script->parse_node());
         if (g_dump_bytecode) {
         if (g_dump_bytecode) {
             for (auto& block : unit.basic_blocks)
             for (auto& block : unit.basic_blocks)
                 block.dump(unit);
                 block.dump(unit);
@@ -329,16 +345,16 @@ inline JSFileResult TestRunner::run_file_test(const String& test_path)
         JS::Bytecode::Interpreter bytecode_interpreter(interpreter->global_object(), interpreter->realm());
         JS::Bytecode::Interpreter bytecode_interpreter(interpreter->global_object(), interpreter->realm());
         bytecode_interpreter.run(unit);
         bytecode_interpreter.run(unit);
     } else {
     } else {
-        interpreter->run(interpreter->global_object(), *m_test_program);
+        interpreter->run(interpreter->global_object(), m_test_script->parse_node());
     }
     }
 
 
     VERIFY(!g_vm->exception());
     VERIFY(!g_vm->exception());
 
 
-    auto file_program = parse_file(test_path);
-    if (file_program.is_error())
-        return { test_path, file_program.error() };
+    auto file_script = parse_script(test_path, interpreter->realm());
+    if (file_script.is_error())
+        return { test_path, file_script.error() };
     if (g_run_bytecode) {
     if (g_run_bytecode) {
-        auto unit = JS::Bytecode::Generator::generate(*file_program.value());
+        auto unit = JS::Bytecode::Generator::generate(file_script.value()->parse_node());
         if (g_dump_bytecode) {
         if (g_dump_bytecode) {
             for (auto& block : unit.basic_blocks)
             for (auto& block : unit.basic_blocks)
                 block.dump(unit);
                 block.dump(unit);
@@ -351,7 +367,7 @@ inline JSFileResult TestRunner::run_file_test(const String& test_path)
         JS::Bytecode::Interpreter bytecode_interpreter(interpreter->global_object(), interpreter->realm());
         JS::Bytecode::Interpreter bytecode_interpreter(interpreter->global_object(), interpreter->realm());
         bytecode_interpreter.run(unit);
         bytecode_interpreter.run(unit);
     } else {
     } else {
-        interpreter->run(interpreter->global_object(), *file_program.value());
+        interpreter->run(interpreter->global_object(), file_script.value()->parse_node());
     }
     }
 
 
     if (g_vm->exception())
     if (g_vm->exception())