Browse Source

LibJS: Implement GeneratorFunctionConstructor::construct

Matthew Olsson 4 years ago
parent
commit
9253fa1bad

+ 30 - 18
Userland/Libraries/LibJS/Runtime/FunctionConstructor.cpp

@@ -4,11 +4,12 @@
  * SPDX-License-Identifier: BSD-2-Clause
  * SPDX-License-Identifier: BSD-2-Clause
  */
  */
 
 
-#include <AK/StringBuilder.h>
 #include <LibJS/AST.h>
 #include <LibJS/AST.h>
 #include <LibJS/Interpreter.h>
 #include <LibJS/Interpreter.h>
+#include <LibJS/Lexer.h>
 #include <LibJS/Parser.h>
 #include <LibJS/Parser.h>
 #include <LibJS/Runtime/Error.h>
 #include <LibJS/Runtime/Error.h>
+#include <LibJS/Runtime/Function.h>
 #include <LibJS/Runtime/FunctionConstructor.h>
 #include <LibJS/Runtime/FunctionConstructor.h>
 #include <LibJS/Runtime/GlobalObject.h>
 #include <LibJS/Runtime/GlobalObject.h>
 
 
@@ -31,48 +32,59 @@ FunctionConstructor::~FunctionConstructor()
 {
 {
 }
 }
 
 
-// 20.2.1.1 Function ( p1, p2, … , pn, body ), https://tc39.es/ecma262/#sec-function-p1-p2-pn-body
-Value FunctionConstructor::call()
-{
-    return construct(*this);
-}
-
-// 20.2.1.1 Function ( p1, p2, … , pn, body ), https://tc39.es/ecma262/#sec-function-p1-p2-pn-body
-Value FunctionConstructor::construct(Function&)
+// 20.2.1.1.1 CreateDynamicFunction ( constructor, newTarget, kind, args ), https://tc39.es/ecma262/#sec-createdynamicfunction
+RefPtr<FunctionExpression> FunctionConstructor::create_dynamic_function_node(GlobalObject& global_object, Function&, FunctionKind kind)
 {
 {
-    auto& vm = this->vm();
+    auto& vm = global_object.vm();
     String parameters_source = "";
     String parameters_source = "";
     String body_source = "";
     String body_source = "";
     if (vm.argument_count() == 1) {
     if (vm.argument_count() == 1) {
-        body_source = vm.argument(0).to_string(global_object());
+        body_source = vm.argument(0).to_string(global_object);
         if (vm.exception())
         if (vm.exception())
             return {};
             return {};
     }
     }
     if (vm.argument_count() > 1) {
     if (vm.argument_count() > 1) {
         Vector<String> parameters;
         Vector<String> parameters;
         for (size_t i = 0; i < vm.argument_count() - 1; ++i) {
         for (size_t i = 0; i < vm.argument_count() - 1; ++i) {
-            parameters.append(vm.argument(i).to_string(global_object()));
+            parameters.append(vm.argument(i).to_string(global_object));
             if (vm.exception())
             if (vm.exception())
                 return {};
                 return {};
         }
         }
         StringBuilder parameters_builder;
         StringBuilder parameters_builder;
         parameters_builder.join(',', parameters);
         parameters_builder.join(',', parameters);
         parameters_source = parameters_builder.build();
         parameters_source = parameters_builder.build();
-        body_source = vm.argument(vm.argument_count() - 1).to_string(global_object());
+        body_source = vm.argument(vm.argument_count() - 1).to_string(global_object);
         if (vm.exception())
         if (vm.exception())
             return {};
             return {};
     }
     }
-    auto source = String::formatted("function anonymous({}\n) {{\n{}\n}}", parameters_source, body_source);
+    auto is_generator = kind == FunctionKind::Generator;
+    auto source = String::formatted("function{} anonymous({}\n) {{\n{}\n}}", is_generator ? "*" : "", parameters_source, body_source);
     auto parser = Parser(Lexer(source));
     auto parser = Parser(Lexer(source));
-    auto function_expression = parser.parse_function_node<FunctionExpression>();
+    auto function = parser.parse_function_node<FunctionExpression>();
     if (parser.has_errors()) {
     if (parser.has_errors()) {
         auto error = parser.errors()[0];
         auto error = parser.errors()[0];
-        vm.throw_exception<SyntaxError>(global_object(), error.to_string());
+        vm.throw_exception<SyntaxError>(global_object, error.to_string());
         return {};
         return {};
     }
     }
 
 
+    return function;
+}
+
+// 20.2.1.1 Function ( p1, p2, … , pn, body ), https://tc39.es/ecma262/#sec-function-p1-p2-pn-body
+Value FunctionConstructor::call()
+{
+    return construct(*this);
+}
+
+// 20.2.1.1 Function ( p1, p2, … , pn, body ), https://tc39.es/ecma262/#sec-function-p1-p2-pn-body
+Value FunctionConstructor::construct(Function& new_target)
+{
+    auto function = create_dynamic_function_node(global_object(), new_target, FunctionKind::Regular);
+    if (!function)
+        return {};
+
     OwnPtr<Interpreter> local_interpreter;
     OwnPtr<Interpreter> local_interpreter;
-    Interpreter* interpreter = vm.interpreter_if_exists();
+    Interpreter* interpreter = vm().interpreter_if_exists();
 
 
     if (!interpreter) {
     if (!interpreter) {
         local_interpreter = Interpreter::create_with_existing_global_object(global_object());
         local_interpreter = Interpreter::create_with_existing_global_object(global_object());
@@ -80,7 +92,7 @@ Value FunctionConstructor::construct(Function&)
     }
     }
 
 
     VM::InterpreterExecutionScope scope(*interpreter);
     VM::InterpreterExecutionScope scope(*interpreter);
-    return function_expression->execute(*interpreter, global_object());
+    return function->execute(*interpreter, global_object());
 }
 }
 
 
 }
 }

+ 2 - 0
Userland/Libraries/LibJS/Runtime/FunctionConstructor.h

@@ -14,6 +14,8 @@ class FunctionConstructor final : public NativeFunction {
     JS_OBJECT(FunctionConstructor, NativeFunction);
     JS_OBJECT(FunctionConstructor, NativeFunction);
 
 
 public:
 public:
+    static RefPtr<FunctionExpression> create_dynamic_function_node(GlobalObject& global_object, Function& new_target, FunctionKind kind);
+
     explicit FunctionConstructor(GlobalObject&);
     explicit FunctionConstructor(GlobalObject&);
     virtual void initialize(GlobalObject&) override;
     virtual void initialize(GlobalObject&) override;
     virtual ~FunctionConstructor() override;
     virtual ~FunctionConstructor() override;

+ 25 - 3
Userland/Libraries/LibJS/Runtime/GeneratorFunctionConstructor.cpp

@@ -4,10 +4,15 @@
  * SPDX-License-Identifier: BSD-2-Clause
  * SPDX-License-Identifier: BSD-2-Clause
  */
  */
 
 
+#include <AK/Debug.h>
+#include <AK/Optional.h>
+#include <LibJS/Bytecode/Interpreter.h>
+#include <LibJS/Lexer.h>
+#include <LibJS/Parser.h>
 #include <LibJS/Runtime/FunctionConstructor.h>
 #include <LibJS/Runtime/FunctionConstructor.h>
-#include <LibJS/Runtime/Function.h>
 #include <LibJS/Runtime/GeneratorFunctionConstructor.h>
 #include <LibJS/Runtime/GeneratorFunctionConstructor.h>
 #include <LibJS/Runtime/GlobalObject.h>
 #include <LibJS/Runtime/GlobalObject.h>
+#include <LibJS/Runtime/ScriptFunction.h>
 
 
 namespace JS {
 namespace JS {
 
 
@@ -38,9 +43,26 @@ Value GeneratorFunctionConstructor::call()
 }
 }
 
 
 // 27.3.1.1 GeneratorFunction ( p1, p2, … , pn, body ), https://tc39.es/ecma262/#sec-generatorfunction
 // 27.3.1.1 GeneratorFunction ( p1, p2, … , pn, body ), https://tc39.es/ecma262/#sec-generatorfunction
-Value GeneratorFunctionConstructor::construct(Function&)
+Value GeneratorFunctionConstructor::construct(Function& new_target)
 {
 {
-    TODO();
+    auto function = FunctionConstructor::create_dynamic_function_node(global_object(), new_target, FunctionKind::Generator);
+    if (!function)
+        return {};
+
+    auto* bytecode_interpreter = Bytecode::Interpreter::current();
+    VERIFY(bytecode_interpreter);
+
+    auto executable = Bytecode::Generator::generate(function->body(), true);
+    auto& passes = JS::Bytecode::Interpreter::optimization_pipeline();
+    passes.perform(executable);
+    if constexpr (JS_BYTECODE_DEBUG) {
+        dbgln("Optimisation passes took {}us", passes.elapsed());
+        dbgln("Compiled Bytecode::Block for function '{}':", function->name());
+        for (auto& block : executable.basic_blocks)
+            block.dump(executable);
+    }
+
+    return ScriptFunction::create(global_object(), function->name(), function->body(), function->parameters(), function->function_length(), vm().current_scope(), FunctionKind::Generator, function->is_strict_mode(), false);
 }
 }
 
 
 }
 }