1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-28 08:35:09 +00:00

LibJS: Implement constructor/non-constructor function calls

This adds Function::construct() for constructor function calls via `new`
keyword. NativeFunction doesn't have constructor behaviour by default,
ScriptFunction simply calls call() in construct()
This commit is contained in:
Linus Groh 2020-04-01 18:31:24 +01:00 committed by Andreas Kling
parent a27884e4be
commit 849e2c77e4
11 changed files with 66 additions and 1 deletions

View file

@ -31,6 +31,7 @@
#include <LibJS/Interpreter.h>
#include <LibJS/Runtime/Array.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/NativeFunction.h>
#include <LibJS/Runtime/PrimitiveString.h>
#include <LibJS/Runtime/ScriptFunction.h>
#include <LibJS/Runtime/Value.h>
@ -87,6 +88,14 @@ Value CallExpression::execute(Interpreter& interpreter) const
if (interpreter.exception())
return {};
if (is_new_expression()) {
if (!callee.is_object()
|| !callee.as_object()->is_function()
|| (callee.as_object()->is_native_function()
&& !static_cast<NativeFunction*>(callee.as_object())->has_constructor()))
return interpreter.throw_exception<Error>("TypeError", String::format("%s is not a constructor", callee.to_string().characters()));
}
if (!callee.is_object() || !callee.as_object()->is_function())
return interpreter.throw_exception<Error>("TypeError", String::format("%s is not a function", callee.to_string().characters()));
@ -103,17 +112,19 @@ Value CallExpression::execute(Interpreter& interpreter) const
}
Object* new_object = nullptr;
Value result;
if (is_new_expression()) {
new_object = interpreter.heap().allocate<Object>();
auto prototype = function->get("prototype");
if (prototype.has_value() && prototype.value().is_object())
new_object->set_prototype(prototype.value().as_object());
call_frame.this_value = new_object;
result = function->construct(interpreter);
} else {
call_frame.this_value = this_value;
result = function->call(interpreter);
}
auto result = function->call(interpreter);
interpreter.pop_call_frame();
if (is_new_expression()) {
@ -955,4 +966,5 @@ void SwitchCase::dump(int indent) const
statement.dump(indent + 1);
}
}
}