1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 14:48:14 +00:00

LibJS: Pass prototype to Function constructors

This commit is contained in:
Andreas Kling 2020-04-17 19:59:32 +02:00
parent 205ac0090d
commit f6d57c82f6
21 changed files with 66 additions and 24 deletions

View file

@ -48,14 +48,14 @@ Value ScopeNode::execute(Interpreter& interpreter) const
Value FunctionDeclaration::execute(Interpreter& interpreter) const
{
auto* function = interpreter.heap().allocate<ScriptFunction>(name(), body(), parameters(), interpreter.current_environment());
auto* function = ScriptFunction::create(interpreter.global_object(), name(), body(), parameters(), interpreter.current_environment());
interpreter.set_variable(name(), function);
return js_undefined();
}
Value FunctionExpression::execute(Interpreter& interpreter) const
{
return interpreter.heap().allocate<ScriptFunction>(name(), body(), parameters(), interpreter.current_environment());
return ScriptFunction::create(interpreter.global_object(), name(), body(), parameters(), interpreter.current_environment());
}
Value ExpressionStatement::execute(Interpreter& interpreter) const

View file

@ -54,6 +54,9 @@ Interpreter::Interpreter()
m_object_prototype = heap().allocate<ObjectPrototype>();
m_function_prototype = heap().allocate<FunctionPrototype>();
static_cast<FunctionPrototype*>(m_function_prototype)->initialize();
static_cast<ObjectPrototype*>(m_object_prototype)->initialize();
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName) \
if (!m_##snake_name##_prototype) \
m_##snake_name##_prototype = heap().allocate<PrototypeName>();

View file

@ -34,7 +34,7 @@
namespace JS {
ArrayConstructor::ArrayConstructor()
: NativeFunction("Array")
: NativeFunction("Array", *interpreter().function_prototype())
{
put("prototype", interpreter().array_prototype());
put("length", Value(1));

View file

@ -33,7 +33,7 @@
namespace JS {
BooleanConstructor::BooleanConstructor()
: NativeFunction("Boolean")
: NativeFunction("Boolean", *interpreter().function_prototype())
{
put("prototype", Value(interpreter().boolean_prototype()));
put("length", Value(1));

View file

@ -34,7 +34,7 @@
namespace JS {
DateConstructor::DateConstructor()
: NativeFunction("Date")
: NativeFunction("Date", *interpreter().function_prototype())
{
put("prototype", interpreter().date_prototype());
put("length", Value(7));

View file

@ -31,7 +31,7 @@
namespace JS {
ErrorConstructor::ErrorConstructor()
: NativeFunction("Error")
: NativeFunction("Error", *interpreter().function_prototype())
{
put("prototype", interpreter().error_prototype());
put("length", Value(1));
@ -56,6 +56,7 @@ Value ErrorConstructor::construct(Interpreter& interpreter)
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName) \
ConstructorName::ConstructorName() \
: NativeFunction(*interpreter().function_prototype()) \
{ \
put("prototype", interpreter().snake_name##_prototype()); \
put("length", Value(1)); \

View file

@ -29,9 +29,9 @@
namespace JS {
Function::Function()
Function::Function(Object& prototype)
{
set_prototype(interpreter().function_prototype());
set_prototype(&prototype);
}
Function::~Function()

View file

@ -41,7 +41,7 @@ public:
virtual LexicalEnvironment* create_environment() = 0;
protected:
Function();
explicit Function(Object& prototype);
virtual const char* class_name() const override { return "Function"; }
private:

View file

@ -35,7 +35,7 @@
namespace JS {
FunctionConstructor::FunctionConstructor()
: NativeFunction("Function")
: NativeFunction("Function", *interpreter().function_prototype())
{
put("prototype", interpreter().function_prototype());
put("length", Value(1));

View file

@ -36,6 +36,10 @@
namespace JS {
FunctionPrototype::FunctionPrototype()
{
}
void FunctionPrototype::initialize()
{
put_native_function("apply", apply, 2);
put_native_function("bind", bind, 1);

View file

@ -33,6 +33,8 @@ namespace JS {
class FunctionPrototype final : public Object {
public:
FunctionPrototype();
void initialize();
virtual ~FunctionPrototype() override;
private:

View file

@ -25,19 +25,32 @@
*/
#include <LibJS/Interpreter.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/NativeFunction.h>
#include <LibJS/Runtime/Value.h>
namespace JS {
NativeFunction::NativeFunction(const FlyString& name, AK::Function<Value(Interpreter&)> native_function)
: m_name(name)
NativeFunction* NativeFunction::create(Interpreter& interpreter, GlobalObject&, const FlyString& name, AK::Function<Value(Interpreter&)> function)
{
return interpreter.heap().allocate<NativeFunction>(name, move(function), *interpreter.function_prototype());
}
NativeFunction::NativeFunction(Object& prototype)
: Function(prototype)
{
}
NativeFunction::NativeFunction(const FlyString& name, AK::Function<Value(Interpreter&)> native_function, Object& prototype)
: Function(prototype)
, m_name(name)
, m_native_function(move(native_function))
{
}
NativeFunction::NativeFunction(const FlyString& name)
: m_name(name)
NativeFunction::NativeFunction(const FlyString& name, Object& prototype)
: Function(prototype)
, m_name(name)
{
}

View file

@ -33,7 +33,9 @@ namespace JS {
class NativeFunction : public Function {
public:
explicit NativeFunction(const FlyString& name, AK::Function<Value(Interpreter&)>);
static NativeFunction* create(Interpreter&, GlobalObject&, const FlyString& name, AK::Function<Value(Interpreter&)>);
explicit NativeFunction(const FlyString& name, AK::Function<Value(Interpreter&)>, Object& prototype);
virtual ~NativeFunction() override;
virtual Value call(Interpreter&) override;
@ -43,8 +45,8 @@ public:
virtual bool has_constructor() const { return false; }
protected:
NativeFunction(const FlyString& name);
NativeFunction() {}
NativeFunction(const FlyString& name, Object& prototype);
explicit NativeFunction(Object& prototype);
private:
virtual bool is_native_function() const override { return true; }

View file

@ -37,7 +37,7 @@
namespace JS {
NumberConstructor::NumberConstructor()
: NativeFunction("Number")
: NativeFunction("Number", *interpreter().function_prototype())
{
put_native_function("isSafeInteger", is_safe_integer, 1);

View file

@ -235,7 +235,7 @@ void Object::put(PropertyName property_name, Value value)
void Object::put_native_function(const FlyString& property_name, AK::Function<Value(Interpreter&)> native_function, i32 length)
{
auto* function = heap().allocate<NativeFunction>(property_name, move(native_function));
auto* function = NativeFunction::create(interpreter(), interpreter().global_object(), property_name, move(native_function));
function->put("length", Value(length));
put(property_name, function);
}

View file

@ -35,7 +35,7 @@
namespace JS {
ObjectConstructor::ObjectConstructor()
: NativeFunction("Object")
: NativeFunction("Object", *interpreter().function_prototype())
{
put("prototype", interpreter().object_prototype());

View file

@ -36,7 +36,12 @@ namespace JS {
ObjectPrototype::ObjectPrototype()
{
set_prototype(nullptr);
}
void ObjectPrototype::initialize()
{
// This must be called after the constructor has returned, so that the below code
// can find the ObjectPrototype through normal paths.
put_native_function("hasOwnProperty", has_own_property, 1);
put_native_function("toString", to_string);
put_native_function("valueOf", value_of);

View file

@ -33,6 +33,8 @@ namespace JS {
class ObjectPrototype final : public Object {
public:
ObjectPrototype();
void initialize();
virtual ~ObjectPrototype() override;
private:

View file

@ -28,13 +28,21 @@
#include <LibJS/AST.h>
#include <LibJS/Interpreter.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/ScriptFunction.h>
#include <LibJS/Runtime/Value.h>
namespace JS {
ScriptFunction::ScriptFunction(const FlyString& name, const Statement& body, Vector<FlyString> parameters, LexicalEnvironment* parent_environment)
: m_name(name)
ScriptFunction* ScriptFunction::create(GlobalObject& global_object, const FlyString& name, const Statement& body, Vector<FlyString> parameters, LexicalEnvironment* parent_environment)
{
auto& interpreter = global_object.interpreter();
return interpreter.heap().allocate<ScriptFunction>(name, body, move(parameters), parent_environment, *interpreter.function_prototype());
}
ScriptFunction::ScriptFunction(const FlyString& name, const Statement& body, Vector<FlyString> parameters, LexicalEnvironment* parent_environment, Object& prototype)
: Function(prototype)
, m_name(name)
, m_body(body)
, m_parameters(move(parameters))
, m_parent_environment(parent_environment)

View file

@ -32,7 +32,9 @@ namespace JS {
class ScriptFunction final : public Function {
public:
ScriptFunction(const FlyString& name, const Statement& body, Vector<FlyString> parameters, LexicalEnvironment* parent_environment);
static ScriptFunction* create(GlobalObject&, const FlyString& name, const Statement& body, Vector<FlyString> parameters, LexicalEnvironment* parent_environment);
ScriptFunction(const FlyString& name, const Statement& body, Vector<FlyString> parameters, LexicalEnvironment* parent_environment, Object& prototype);
virtual ~ScriptFunction();
const Statement& body() const { return m_body; }

View file

@ -33,7 +33,7 @@
namespace JS {
StringConstructor::StringConstructor()
: NativeFunction("String")
: NativeFunction("String", *interpreter().function_prototype())
{
put("prototype", interpreter().string_prototype());
put("length", Value(1));