mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 04:07:44 +00:00
LibJS: Explicitly pass a "Function& new_target" to Function::construct
This allows the proxy handler to pass the proper new.target to construct handlers.
This commit is contained in:
parent
19411e22d0
commit
bda39ef7ab
38 changed files with 63 additions and 50 deletions
|
@ -268,7 +268,7 @@ Value Interpreter::construct(Function& function, Function& new_target, Optional<
|
||||||
// If we are a Derived constructor, |this| has not been constructed before super is called.
|
// If we are a Derived constructor, |this| has not been constructed before super is called.
|
||||||
Value this_value = function.constructor_kind() == Function::ConstructorKind::Base ? new_object : Value {};
|
Value this_value = function.constructor_kind() == Function::ConstructorKind::Base ? new_object : Value {};
|
||||||
call_frame.this_value = this_value;
|
call_frame.this_value = this_value;
|
||||||
auto result = function.construct(*this);
|
auto result = function.construct(*this, new_target);
|
||||||
|
|
||||||
this_value = current_environment()->get_this_binding();
|
this_value = current_environment()->get_this_binding();
|
||||||
pop_call_frame();
|
pop_call_frame();
|
||||||
|
|
|
@ -79,7 +79,7 @@ Value ArrayConstructor::call(Interpreter& interpreter)
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value ArrayConstructor::construct(Interpreter& interpreter)
|
Value ArrayConstructor::construct(Interpreter& interpreter, Function&)
|
||||||
{
|
{
|
||||||
return call(interpreter);
|
return call(interpreter);
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ public:
|
||||||
virtual ~ArrayConstructor() override;
|
virtual ~ArrayConstructor() override;
|
||||||
|
|
||||||
virtual Value call(Interpreter&) override;
|
virtual Value call(Interpreter&) override;
|
||||||
virtual Value construct(Interpreter&) override;
|
virtual Value construct(Interpreter&, Function& new_target) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual bool has_constructor() const override { return true; }
|
virtual bool has_constructor() const override { return true; }
|
||||||
|
|
|
@ -72,7 +72,7 @@ Value BigIntConstructor::call(Interpreter& interpreter)
|
||||||
return bigint;
|
return bigint;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value BigIntConstructor::construct(Interpreter& interpreter)
|
Value BigIntConstructor::construct(Interpreter& interpreter, Function&)
|
||||||
{
|
{
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotAConstructor, "BigInt");
|
interpreter.throw_exception<TypeError>(ErrorType::NotAConstructor, "BigInt");
|
||||||
return {};
|
return {};
|
||||||
|
|
|
@ -39,7 +39,7 @@ public:
|
||||||
virtual ~BigIntConstructor() override;
|
virtual ~BigIntConstructor() override;
|
||||||
|
|
||||||
virtual Value call(Interpreter&) override;
|
virtual Value call(Interpreter&) override;
|
||||||
virtual Value construct(Interpreter&) override;
|
virtual Value construct(Interpreter&, Function& new_target) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual bool has_constructor() const override { return true; }
|
virtual bool has_constructor() const override { return true; }
|
||||||
|
|
|
@ -54,7 +54,7 @@ Value BooleanConstructor::call(Interpreter& interpreter)
|
||||||
return Value(interpreter.argument(0).to_boolean());
|
return Value(interpreter.argument(0).to_boolean());
|
||||||
}
|
}
|
||||||
|
|
||||||
Value BooleanConstructor::construct(Interpreter& interpreter)
|
Value BooleanConstructor::construct(Interpreter& interpreter, Function&)
|
||||||
{
|
{
|
||||||
return BooleanObject::create(global_object(), interpreter.argument(0).to_boolean());
|
return BooleanObject::create(global_object(), interpreter.argument(0).to_boolean());
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ public:
|
||||||
virtual ~BooleanConstructor() override;
|
virtual ~BooleanConstructor() override;
|
||||||
|
|
||||||
virtual Value call(Interpreter&) override;
|
virtual Value call(Interpreter&) override;
|
||||||
virtual Value construct(Interpreter&) override;
|
virtual Value construct(Interpreter&, Function& new_target) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual bool has_constructor() const override { return true; }
|
virtual bool has_constructor() const override { return true; }
|
||||||
|
|
|
@ -54,14 +54,14 @@ Value BoundFunction::call(Interpreter& interpreter)
|
||||||
return m_target_function->call(interpreter);
|
return m_target_function->call(interpreter);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value BoundFunction::construct(Interpreter& interpreter)
|
Value BoundFunction::construct(Interpreter& interpreter, Function& new_target)
|
||||||
{
|
{
|
||||||
if (auto this_value = interpreter.this_value(global_object()); m_constructor_prototype && this_value.is_object()) {
|
if (auto this_value = interpreter.this_value(global_object()); m_constructor_prototype && this_value.is_object()) {
|
||||||
this_value.as_object().set_prototype(m_constructor_prototype);
|
this_value.as_object().set_prototype(m_constructor_prototype);
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return m_target_function->construct(interpreter);
|
return m_target_function->construct(interpreter, new_target);
|
||||||
}
|
}
|
||||||
|
|
||||||
LexicalEnvironment* BoundFunction::create_environment()
|
LexicalEnvironment* BoundFunction::create_environment()
|
||||||
|
|
|
@ -40,7 +40,7 @@ public:
|
||||||
|
|
||||||
virtual Value call(Interpreter& interpreter) override;
|
virtual Value call(Interpreter& interpreter) override;
|
||||||
|
|
||||||
virtual Value construct(Interpreter& interpreter) override;
|
virtual Value construct(Interpreter&, Function& new_target) override;
|
||||||
|
|
||||||
virtual LexicalEnvironment* create_environment() override;
|
virtual LexicalEnvironment* create_environment() override;
|
||||||
|
|
||||||
|
|
|
@ -54,13 +54,13 @@ DateConstructor::~DateConstructor()
|
||||||
|
|
||||||
Value DateConstructor::call(Interpreter& interpreter)
|
Value DateConstructor::call(Interpreter& interpreter)
|
||||||
{
|
{
|
||||||
auto date = construct(interpreter);
|
auto date = construct(interpreter, *this);
|
||||||
if (!date.is_object())
|
if (!date.is_object())
|
||||||
return {};
|
return {};
|
||||||
return js_string(interpreter, static_cast<Date&>(date.as_object()).string());
|
return js_string(interpreter, static_cast<Date&>(date.as_object()).string());
|
||||||
}
|
}
|
||||||
|
|
||||||
Value DateConstructor::construct(Interpreter&)
|
Value DateConstructor::construct(Interpreter&, Function&)
|
||||||
{
|
{
|
||||||
// TODO: Support args
|
// TODO: Support args
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
|
|
|
@ -39,7 +39,7 @@ public:
|
||||||
virtual ~DateConstructor() override;
|
virtual ~DateConstructor() override;
|
||||||
|
|
||||||
virtual Value call(Interpreter&) override;
|
virtual Value call(Interpreter&) override;
|
||||||
virtual Value construct(Interpreter&) override;
|
virtual Value construct(Interpreter&, Function& new_target) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual bool has_constructor() const override { return true; }
|
virtual bool has_constructor() const override { return true; }
|
||||||
|
|
|
@ -49,10 +49,10 @@ ErrorConstructor::~ErrorConstructor()
|
||||||
|
|
||||||
Value ErrorConstructor::call(Interpreter& interpreter)
|
Value ErrorConstructor::call(Interpreter& interpreter)
|
||||||
{
|
{
|
||||||
return construct(interpreter);
|
return construct(interpreter, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value ErrorConstructor::construct(Interpreter& interpreter)
|
Value ErrorConstructor::construct(Interpreter& interpreter, Function&)
|
||||||
{
|
{
|
||||||
String message = "";
|
String message = "";
|
||||||
if (!interpreter.call_frame().arguments.is_empty() && !interpreter.call_frame().arguments[0].is_undefined()) {
|
if (!interpreter.call_frame().arguments.is_empty() && !interpreter.call_frame().arguments[0].is_undefined()) {
|
||||||
|
@ -77,9 +77,9 @@ Value ErrorConstructor::construct(Interpreter& interpreter)
|
||||||
ConstructorName::~ConstructorName() { } \
|
ConstructorName::~ConstructorName() { } \
|
||||||
Value ConstructorName::call(Interpreter& interpreter) \
|
Value ConstructorName::call(Interpreter& interpreter) \
|
||||||
{ \
|
{ \
|
||||||
return construct(interpreter); \
|
return construct(interpreter, *this); \
|
||||||
} \
|
} \
|
||||||
Value ConstructorName::construct(Interpreter& interpreter) \
|
Value ConstructorName::construct(Interpreter& interpreter, Function&) \
|
||||||
{ \
|
{ \
|
||||||
String message = ""; \
|
String message = ""; \
|
||||||
if (!interpreter.call_frame().arguments.is_empty() && !interpreter.call_frame().arguments[0].is_undefined()) { \
|
if (!interpreter.call_frame().arguments.is_empty() && !interpreter.call_frame().arguments[0].is_undefined()) { \
|
||||||
|
|
|
@ -40,7 +40,7 @@ public:
|
||||||
virtual ~ErrorConstructor() override;
|
virtual ~ErrorConstructor() override;
|
||||||
|
|
||||||
virtual Value call(Interpreter&) override;
|
virtual Value call(Interpreter&) override;
|
||||||
virtual Value construct(Interpreter&) override;
|
virtual Value construct(Interpreter&, Function& new_target) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual bool has_constructor() const override { return true; }
|
virtual bool has_constructor() const override { return true; }
|
||||||
|
@ -55,7 +55,7 @@ private:
|
||||||
virtual void initialize(Interpreter&, GlobalObject&) override; \
|
virtual void initialize(Interpreter&, GlobalObject&) override; \
|
||||||
virtual ~ConstructorName() override; \
|
virtual ~ConstructorName() override; \
|
||||||
virtual Value call(Interpreter&) override; \
|
virtual Value call(Interpreter&) override; \
|
||||||
virtual Value construct(Interpreter&) override; \
|
virtual Value construct(Interpreter&, Function& new_target) override; \
|
||||||
\
|
\
|
||||||
private: \
|
private: \
|
||||||
virtual bool has_constructor() const override { return true; } \
|
virtual bool has_constructor() const override { return true; } \
|
||||||
|
|
|
@ -68,7 +68,7 @@
|
||||||
"Object prototype must not be %s on a super property access") \
|
"Object prototype must not be %s on a super property access") \
|
||||||
M(ObjectPrototypeWrongType, "Prototype must be an object or null") \
|
M(ObjectPrototypeWrongType, "Prototype must be an object or null") \
|
||||||
M(ProxyCallWithNew, "Proxy must be called with the 'new' operator") \
|
M(ProxyCallWithNew, "Proxy must be called with the 'new' operator") \
|
||||||
M(ProxyConstructBadReturnType, "Proxy handler's construct trap violates invariant: must return" \
|
M(ProxyConstructBadReturnType, "Proxy handler's construct trap violates invariant: must return " \
|
||||||
"an object") \
|
"an object") \
|
||||||
M(ProxyConstructorBadType, "Expected %s argument of Proxy constructor to be object, got %s") \
|
M(ProxyConstructorBadType, "Expected %s argument of Proxy constructor to be object, got %s") \
|
||||||
M(ProxyDefinePropExistingConfigurable, "Proxy handler's defineProperty trap violates " \
|
M(ProxyDefinePropExistingConfigurable, "Proxy handler's defineProperty trap violates " \
|
||||||
|
|
|
@ -44,7 +44,7 @@ public:
|
||||||
virtual void initialize(Interpreter&, GlobalObject&) override { }
|
virtual void initialize(Interpreter&, GlobalObject&) override { }
|
||||||
|
|
||||||
virtual Value call(Interpreter&) = 0;
|
virtual Value call(Interpreter&) = 0;
|
||||||
virtual Value construct(Interpreter&) = 0;
|
virtual Value construct(Interpreter&, Function& new_target) = 0;
|
||||||
virtual const FlyString& name() const = 0;
|
virtual const FlyString& name() const = 0;
|
||||||
virtual LexicalEnvironment* create_environment() = 0;
|
virtual LexicalEnvironment* create_environment() = 0;
|
||||||
|
|
||||||
|
|
|
@ -53,10 +53,10 @@ FunctionConstructor::~FunctionConstructor()
|
||||||
|
|
||||||
Value FunctionConstructor::call(Interpreter& interpreter)
|
Value FunctionConstructor::call(Interpreter& interpreter)
|
||||||
{
|
{
|
||||||
return construct(interpreter);
|
return construct(interpreter, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value FunctionConstructor::construct(Interpreter& interpreter)
|
Value FunctionConstructor::construct(Interpreter& interpreter, Function&)
|
||||||
{
|
{
|
||||||
String parameters_source = "";
|
String parameters_source = "";
|
||||||
String body_source = "";
|
String body_source = "";
|
||||||
|
|
|
@ -39,7 +39,7 @@ public:
|
||||||
virtual ~FunctionConstructor() override;
|
virtual ~FunctionConstructor() override;
|
||||||
|
|
||||||
virtual Value call(Interpreter&) override;
|
virtual Value call(Interpreter&) override;
|
||||||
virtual Value construct(Interpreter&) override;
|
virtual Value construct(Interpreter&, Function& new_target) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual bool has_constructor() const override { return true; }
|
virtual bool has_constructor() const override { return true; }
|
||||||
|
|
|
@ -63,7 +63,7 @@ Value NativeFunction::call(Interpreter& interpreter)
|
||||||
return m_native_function(interpreter, global_object());
|
return m_native_function(interpreter, global_object());
|
||||||
}
|
}
|
||||||
|
|
||||||
Value NativeFunction::construct(Interpreter&)
|
Value NativeFunction::construct(Interpreter&, Function&)
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ public:
|
||||||
virtual ~NativeFunction() override;
|
virtual ~NativeFunction() override;
|
||||||
|
|
||||||
virtual Value call(Interpreter&) override;
|
virtual Value call(Interpreter&) override;
|
||||||
virtual Value construct(Interpreter&) override;
|
virtual Value construct(Interpreter&, Function& new_target) override;
|
||||||
|
|
||||||
virtual const FlyString& name() const override { return m_name; };
|
virtual const FlyString& name() const override { return m_name; };
|
||||||
virtual bool has_constructor() const { return false; }
|
virtual bool has_constructor() const { return false; }
|
||||||
|
|
|
@ -72,7 +72,7 @@ Value NumberConstructor::call(Interpreter& interpreter)
|
||||||
return interpreter.argument(0).to_number(interpreter);
|
return interpreter.argument(0).to_number(interpreter);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value NumberConstructor::construct(Interpreter& interpreter)
|
Value NumberConstructor::construct(Interpreter& interpreter, Function&)
|
||||||
{
|
{
|
||||||
double number = 0;
|
double number = 0;
|
||||||
if (interpreter.argument_count()) {
|
if (interpreter.argument_count()) {
|
||||||
|
|
|
@ -39,7 +39,7 @@ public:
|
||||||
virtual ~NumberConstructor() override;
|
virtual ~NumberConstructor() override;
|
||||||
|
|
||||||
virtual Value call(Interpreter&) override;
|
virtual Value call(Interpreter&) override;
|
||||||
virtual Value construct(Interpreter&) override;
|
virtual Value construct(Interpreter&, Function& new_target) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual bool has_constructor() const override { return true; }
|
virtual bool has_constructor() const override { return true; }
|
||||||
|
|
|
@ -69,7 +69,7 @@ Value ObjectConstructor::call(Interpreter& interpreter)
|
||||||
return Object::create_empty(interpreter, global_object());
|
return Object::create_empty(interpreter, global_object());
|
||||||
}
|
}
|
||||||
|
|
||||||
Value ObjectConstructor::construct(Interpreter& interpreter)
|
Value ObjectConstructor::construct(Interpreter& interpreter, Function&)
|
||||||
{
|
{
|
||||||
return call(interpreter);
|
return call(interpreter);
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ public:
|
||||||
virtual ~ObjectConstructor() override;
|
virtual ~ObjectConstructor() override;
|
||||||
|
|
||||||
virtual Value call(Interpreter&) override;
|
virtual Value call(Interpreter&) override;
|
||||||
virtual Value construct(Interpreter&) override;
|
virtual Value construct(Interpreter&, Function& new_target) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual bool has_constructor() const override { return true; }
|
virtual bool has_constructor() const override { return true; }
|
||||||
|
|
|
@ -54,7 +54,7 @@ Value ProxyConstructor::call(Interpreter& interpreter)
|
||||||
return interpreter.throw_exception<TypeError>(ErrorType::ProxyCallWithNew);
|
return interpreter.throw_exception<TypeError>(ErrorType::ProxyCallWithNew);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value ProxyConstructor::construct(Interpreter& interpreter)
|
Value ProxyConstructor::construct(Interpreter& interpreter, Function&)
|
||||||
{
|
{
|
||||||
if (interpreter.argument_count() < 2)
|
if (interpreter.argument_count() < 2)
|
||||||
return interpreter.throw_exception<TypeError>(ErrorType::ProxyTwoArguments);
|
return interpreter.throw_exception<TypeError>(ErrorType::ProxyTwoArguments);
|
||||||
|
|
|
@ -39,7 +39,7 @@ public:
|
||||||
virtual ~ProxyConstructor() override;
|
virtual ~ProxyConstructor() override;
|
||||||
|
|
||||||
virtual Value call(Interpreter&) override;
|
virtual Value call(Interpreter&) override;
|
||||||
virtual Value construct(Interpreter&) override;
|
virtual Value construct(Interpreter&, Function& new_target) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual bool has_constructor() const override { return true; }
|
virtual bool has_constructor() const override { return true; }
|
||||||
|
|
|
@ -501,7 +501,7 @@ Value ProxyObject::call(Interpreter& interpreter) {
|
||||||
return interpreter.call(trap.as_function(), Value(&m_handler), move(arguments));
|
return interpreter.call(trap.as_function(), Value(&m_handler), move(arguments));
|
||||||
}
|
}
|
||||||
|
|
||||||
Value ProxyObject::construct(Interpreter& interpreter) {
|
Value ProxyObject::construct(Interpreter& interpreter, Function& new_target) {
|
||||||
if (!is_function())
|
if (!is_function())
|
||||||
return interpreter.throw_exception<TypeError>(ErrorType::NotAConstructor, Value(this).to_string_without_side_effects().characters());
|
return interpreter.throw_exception<TypeError>(ErrorType::NotAConstructor, Value(this).to_string_without_side_effects().characters());
|
||||||
|
|
||||||
|
@ -513,7 +513,7 @@ Value ProxyObject::construct(Interpreter& interpreter) {
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
return {};
|
return {};
|
||||||
if (trap.is_empty() || trap.is_undefined() || trap.is_null())
|
if (trap.is_empty() || trap.is_undefined() || trap.is_null())
|
||||||
return static_cast<Function&>(m_target).construct(interpreter);
|
return static_cast<Function&>(m_target).construct(interpreter, new_target);
|
||||||
if (!trap.is_function())
|
if (!trap.is_function())
|
||||||
return interpreter.throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "construct");
|
return interpreter.throw_exception<TypeError>(ErrorType::ProxyInvalidTrap, "construct");
|
||||||
|
|
||||||
|
@ -524,9 +524,7 @@ Value ProxyObject::construct(Interpreter& interpreter) {
|
||||||
arguments_array->indexed_properties().append(argument);
|
arguments_array->indexed_properties().append(argument);
|
||||||
});
|
});
|
||||||
arguments.values().append(arguments_array);
|
arguments.values().append(arguments_array);
|
||||||
// FIXME: We need access to the actual newTarget property here. This is just
|
arguments.values().append(Value(&new_target));
|
||||||
// a quick fix
|
|
||||||
arguments.values().append(Value(this));
|
|
||||||
auto result = interpreter.call(trap.as_function(), Value(&m_handler), move(arguments));
|
auto result = interpreter.call(trap.as_function(), Value(&m_handler), move(arguments));
|
||||||
if (!result.is_object())
|
if (!result.is_object())
|
||||||
return interpreter.throw_exception<TypeError>(ErrorType::ProxyConstructBadReturnType);
|
return interpreter.throw_exception<TypeError>(ErrorType::ProxyConstructBadReturnType);
|
||||||
|
|
|
@ -40,7 +40,7 @@ public:
|
||||||
virtual ~ProxyObject() override;
|
virtual ~ProxyObject() override;
|
||||||
|
|
||||||
virtual Value call(Interpreter&) override;
|
virtual Value call(Interpreter&) override;
|
||||||
virtual Value construct(Interpreter&) override;
|
virtual Value construct(Interpreter&, Function& new_target) override;
|
||||||
virtual const FlyString& name() const override;
|
virtual const FlyString& name() const override;
|
||||||
virtual LexicalEnvironment* create_environment() override;
|
virtual LexicalEnvironment* create_environment() override;
|
||||||
|
|
||||||
|
|
|
@ -50,10 +50,10 @@ RegExpConstructor::~RegExpConstructor()
|
||||||
|
|
||||||
Value RegExpConstructor::call(Interpreter& interpreter)
|
Value RegExpConstructor::call(Interpreter& interpreter)
|
||||||
{
|
{
|
||||||
return construct(interpreter);
|
return construct(interpreter, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value RegExpConstructor::construct(Interpreter& interpreter)
|
Value RegExpConstructor::construct(Interpreter& interpreter, Function&)
|
||||||
{
|
{
|
||||||
if (!interpreter.argument_count())
|
if (!interpreter.argument_count())
|
||||||
return RegExpObject::create(global_object(), "(?:)", "");
|
return RegExpObject::create(global_object(), "(?:)", "");
|
||||||
|
|
|
@ -39,7 +39,7 @@ public:
|
||||||
virtual ~RegExpConstructor() override;
|
virtual ~RegExpConstructor() override;
|
||||||
|
|
||||||
virtual Value call(Interpreter&) override;
|
virtual Value call(Interpreter&) override;
|
||||||
virtual Value construct(Interpreter&) override;
|
virtual Value construct(Interpreter&, Function& new_target) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual bool has_constructor() const override { return true; }
|
virtual bool has_constructor() const override { return true; }
|
||||||
|
|
|
@ -133,7 +133,7 @@ Value ScriptFunction::call(Interpreter& interpreter)
|
||||||
return interpreter.run(global_object(), m_body, arguments, ScopeType::Function);
|
return interpreter.run(global_object(), m_body, arguments, ScopeType::Function);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value ScriptFunction::construct(Interpreter& interpreter)
|
Value ScriptFunction::construct(Interpreter& interpreter, Function&)
|
||||||
{
|
{
|
||||||
if (m_is_arrow_function)
|
if (m_is_arrow_function)
|
||||||
return interpreter.throw_exception<TypeError>(ErrorType::NotAConstructor, m_name.characters());
|
return interpreter.throw_exception<TypeError>(ErrorType::NotAConstructor, m_name.characters());
|
||||||
|
|
|
@ -45,7 +45,7 @@ public:
|
||||||
const Vector<FunctionNode::Parameter>& parameters() const { return m_parameters; };
|
const Vector<FunctionNode::Parameter>& parameters() const { return m_parameters; };
|
||||||
|
|
||||||
virtual Value call(Interpreter&) override;
|
virtual Value call(Interpreter&) override;
|
||||||
virtual Value construct(Interpreter&) override;
|
virtual Value construct(Interpreter&, Function& new_target) override;
|
||||||
|
|
||||||
virtual const FlyString& name() const override { return m_name; };
|
virtual const FlyString& name() const override { return m_name; };
|
||||||
void set_name(const FlyString& name) { m_name = name; };
|
void set_name(const FlyString& name) { m_name = name; };
|
||||||
|
|
|
@ -65,7 +65,7 @@ Value StringConstructor::call(Interpreter& interpreter)
|
||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value StringConstructor::construct(Interpreter& interpreter)
|
Value StringConstructor::construct(Interpreter& interpreter, Function&)
|
||||||
{
|
{
|
||||||
PrimitiveString* primitive_string = nullptr;
|
PrimitiveString* primitive_string = nullptr;
|
||||||
if (!interpreter.argument_count())
|
if (!interpreter.argument_count())
|
||||||
|
|
|
@ -39,7 +39,7 @@ public:
|
||||||
virtual ~StringConstructor() override;
|
virtual ~StringConstructor() override;
|
||||||
|
|
||||||
virtual Value call(Interpreter&) override;
|
virtual Value call(Interpreter&) override;
|
||||||
virtual Value construct(Interpreter&) override;
|
virtual Value construct(Interpreter&, Function& new_target) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual bool has_constructor() const override { return true; }
|
virtual bool has_constructor() const override { return true; }
|
||||||
|
|
|
@ -74,7 +74,7 @@ Value SymbolConstructor::call(Interpreter& interpreter)
|
||||||
return js_symbol(interpreter, interpreter.argument(0).to_string(interpreter), false);
|
return js_symbol(interpreter, interpreter.argument(0).to_string(interpreter), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value SymbolConstructor::construct(Interpreter& interpreter)
|
Value SymbolConstructor::construct(Interpreter& interpreter, Function&)
|
||||||
{
|
{
|
||||||
interpreter.throw_exception<TypeError>(ErrorType::NotAConstructor, "Symbol");
|
interpreter.throw_exception<TypeError>(ErrorType::NotAConstructor, "Symbol");
|
||||||
return {};
|
return {};
|
||||||
|
|
|
@ -39,7 +39,7 @@ public:
|
||||||
virtual ~SymbolConstructor() override;
|
virtual ~SymbolConstructor() override;
|
||||||
|
|
||||||
virtual Value call(Interpreter&) override;
|
virtual Value call(Interpreter&) override;
|
||||||
virtual Value construct(Interpreter&) override;
|
virtual Value construct(Interpreter&, Function& new_target) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual bool has_constructor() const override { return true; }
|
virtual bool has_constructor() const override { return true; }
|
||||||
|
|
|
@ -27,6 +27,21 @@ try {
|
||||||
assert(new p(15).x === 15);
|
assert(new p(15).x === 15);
|
||||||
assert(new p(15, true).x === 30);
|
assert(new p(15, true).x === 30);
|
||||||
|
|
||||||
|
let p;
|
||||||
|
function theNewTarget() {};
|
||||||
|
const handler = {
|
||||||
|
construct(target, arguments, newTarget) {
|
||||||
|
assert(target === f);
|
||||||
|
assert(newTarget === theNewTarget);
|
||||||
|
if (arguments[1])
|
||||||
|
return Reflect.construct(target, [arguments[0] * 2], newTarget);
|
||||||
|
return Reflect.construct(target, arguments, newTarget);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
p = new Proxy(f, handler);
|
||||||
|
|
||||||
|
Reflect.construct(p, [15], theNewTarget);
|
||||||
|
|
||||||
// Invariants
|
// Invariants
|
||||||
[{}, [], new Proxy({}, {})].forEach(item => {
|
[{}, [], new Proxy({}, {})].forEach(item => {
|
||||||
assertThrowsError(() => {
|
assertThrowsError(() => {
|
||||||
|
|
|
@ -59,10 +59,10 @@ XMLHttpRequestConstructor::~XMLHttpRequestConstructor()
|
||||||
|
|
||||||
JS::Value XMLHttpRequestConstructor::call(JS::Interpreter& interpreter)
|
JS::Value XMLHttpRequestConstructor::call(JS::Interpreter& interpreter)
|
||||||
{
|
{
|
||||||
return construct(interpreter);
|
return construct(interpreter, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS::Value XMLHttpRequestConstructor::construct(JS::Interpreter& interpreter)
|
JS::Value XMLHttpRequestConstructor::construct(JS::Interpreter& interpreter, Function&)
|
||||||
{
|
{
|
||||||
auto& window = static_cast<WindowObject&>(global_object());
|
auto& window = static_cast<WindowObject&>(global_object());
|
||||||
return interpreter.heap().allocate<XMLHttpRequestWrapper>(window, window, XMLHttpRequest::create(window.impl()));
|
return interpreter.heap().allocate<XMLHttpRequestWrapper>(window, window, XMLHttpRequest::create(window.impl()));
|
||||||
|
|
|
@ -38,7 +38,7 @@ public:
|
||||||
virtual ~XMLHttpRequestConstructor() override;
|
virtual ~XMLHttpRequestConstructor() override;
|
||||||
|
|
||||||
virtual JS::Value call(JS::Interpreter&) override;
|
virtual JS::Value call(JS::Interpreter&) override;
|
||||||
virtual JS::Value construct(JS::Interpreter&) override;
|
virtual JS::Value construct(JS::Interpreter& interpreter, Function& new_target) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual bool has_constructor() const override { return true; }
|
virtual bool has_constructor() const override { return true; }
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue