mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 20:47:45 +00:00
LibJS: Split out NewExpression evaluation from CallExpression
This patch adds an override for NewExpression::execute() in the AST interpreter to separate the logic from CallExpression. As a result, both evaluation functions are simplified. Both expressions are still largely non-conforming, but this makes it easier to work on improving that since we can now deal with them separately. :^)
This commit is contained in:
parent
bad1acf137
commit
814549b846
2 changed files with 66 additions and 44 deletions
|
@ -192,6 +192,45 @@ static void argument_list_evaluation(Interpreter& interpreter, GlobalObject& glo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Value NewExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const
|
||||||
|
{
|
||||||
|
InterpreterNodeScope node_scope { interpreter, *this };
|
||||||
|
auto& vm = interpreter.vm();
|
||||||
|
|
||||||
|
auto [this_value, callee] = compute_this_and_callee(interpreter, global_object);
|
||||||
|
if (vm.exception())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (!callee.is_function() || (is<NativeFunction>(callee.as_object()) && !static_cast<NativeFunction&>(callee.as_object()).has_constructor())) {
|
||||||
|
throw_type_error_for_callee(interpreter, global_object, callee, "constructor"sv);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
MarkedValueList arg_list(vm.heap());
|
||||||
|
argument_list_evaluation(interpreter, global_object, m_arguments, arg_list);
|
||||||
|
if (interpreter.exception())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
auto& function = callee.as_function();
|
||||||
|
return vm.construct(function, function, move(arg_list));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CallExpression::throw_type_error_for_callee(Interpreter& interpreter, GlobalObject& global_object, Value callee_value, StringView call_type) const
|
||||||
|
{
|
||||||
|
auto& vm = interpreter.vm();
|
||||||
|
if (is<Identifier>(*m_callee) || is<MemberExpression>(*m_callee)) {
|
||||||
|
String expression_string;
|
||||||
|
if (is<Identifier>(*m_callee)) {
|
||||||
|
expression_string = static_cast<Identifier const&>(*m_callee).string();
|
||||||
|
} else {
|
||||||
|
expression_string = static_cast<MemberExpression const&>(*m_callee).to_string_approximation();
|
||||||
|
}
|
||||||
|
vm.throw_exception<TypeError>(global_object, ErrorType::IsNotAEvaluatedFrom, callee_value.to_string_without_side_effects(), call_type, expression_string);
|
||||||
|
} else {
|
||||||
|
vm.throw_exception<TypeError>(global_object, ErrorType::IsNotA, callee_value.to_string_without_side_effects(), call_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Value CallExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const
|
Value CallExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const
|
||||||
{
|
{
|
||||||
InterpreterNodeScope node_scope { interpreter, *this };
|
InterpreterNodeScope node_scope { interpreter, *this };
|
||||||
|
@ -202,44 +241,28 @@ Value CallExpression::execute(Interpreter& interpreter, GlobalObject& global_obj
|
||||||
|
|
||||||
VERIFY(!callee.is_empty());
|
VERIFY(!callee.is_empty());
|
||||||
|
|
||||||
if (!callee.is_function()
|
if (!callee.is_function()) {
|
||||||
|| (is<NewExpression>(*this) && (is<NativeFunction>(callee.as_object()) && !static_cast<NativeFunction&>(callee.as_object()).has_constructor()))) {
|
throw_type_error_for_callee(interpreter, global_object, callee, "function"sv);
|
||||||
String error_message;
|
|
||||||
auto call_type = is<NewExpression>(*this) ? "constructor" : "function";
|
|
||||||
if (is<Identifier>(*m_callee) || is<MemberExpression>(*m_callee)) {
|
|
||||||
String expression_string;
|
|
||||||
if (is<Identifier>(*m_callee)) {
|
|
||||||
expression_string = static_cast<Identifier const&>(*m_callee).string();
|
|
||||||
} else {
|
|
||||||
expression_string = static_cast<MemberExpression const&>(*m_callee).to_string_approximation();
|
|
||||||
}
|
|
||||||
vm.throw_exception<TypeError>(global_object, ErrorType::IsNotAEvaluatedFrom, callee.to_string_without_side_effects(), call_type, expression_string);
|
|
||||||
} else {
|
|
||||||
vm.throw_exception<TypeError>(global_object, ErrorType::IsNotA, callee.to_string_without_side_effects(), call_type);
|
|
||||||
}
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& function = callee.as_function();
|
|
||||||
|
|
||||||
MarkedValueList arg_list(vm.heap());
|
MarkedValueList arg_list(vm.heap());
|
||||||
argument_list_evaluation(interpreter, global_object, m_arguments, arg_list);
|
argument_list_evaluation(interpreter, global_object, m_arguments, arg_list);
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
if (!is<NewExpression>(*this) && is<Identifier>(*m_callee) && static_cast<Identifier const&>(*m_callee).string() == vm.names.eval.as_string() && &callee.as_function() == global_object.eval_function()) {
|
auto& function = callee.as_function();
|
||||||
|
|
||||||
|
if (is<Identifier>(*m_callee) && static_cast<Identifier const&>(*m_callee).string() == vm.names.eval.as_string() && &function == global_object.eval_function()) {
|
||||||
auto script_value = arg_list.size() == 0 ? js_undefined() : arg_list[0];
|
auto script_value = arg_list.size() == 0 ? js_undefined() : arg_list[0];
|
||||||
return perform_eval(script_value, global_object, vm.in_strict_mode() ? CallerMode::Strict : CallerMode::NonStrict, EvalMode::Direct);
|
return perform_eval(script_value, global_object, vm.in_strict_mode() ? CallerMode::Strict : CallerMode::NonStrict, EvalMode::Direct);
|
||||||
}
|
}
|
||||||
|
|
||||||
vm.running_execution_context().current_node = interpreter.current_node();
|
|
||||||
Object* new_object = nullptr;
|
|
||||||
Value result;
|
Value result;
|
||||||
if (is<NewExpression>(*this)) {
|
|
||||||
result = vm.construct(function, function, move(arg_list));
|
if (!is<SuperExpression>(*m_callee))
|
||||||
if (result.is_object())
|
return vm.call(function, this_value, move(arg_list));
|
||||||
new_object = &result.as_object();
|
|
||||||
} else if (is<SuperExpression>(*m_callee)) {
|
|
||||||
auto* super_constructor = get_super_constructor(interpreter.vm());
|
auto* super_constructor = get_super_constructor(interpreter.vm());
|
||||||
// FIXME: Functions should track their constructor kind.
|
// FIXME: Functions should track their constructor kind.
|
||||||
if (!super_constructor || !super_constructor->is_function()) {
|
if (!super_constructor || !super_constructor->is_function()) {
|
||||||
|
@ -252,18 +275,10 @@ Value CallExpression::execute(Interpreter& interpreter, GlobalObject& global_obj
|
||||||
|
|
||||||
auto& this_er = get_this_environment(interpreter.vm());
|
auto& this_er = get_this_environment(interpreter.vm());
|
||||||
verify_cast<FunctionEnvironment>(this_er).bind_this_value(global_object, result);
|
verify_cast<FunctionEnvironment>(this_er).bind_this_value(global_object, result);
|
||||||
} else {
|
|
||||||
result = vm.call(function, this_value, move(arg_list));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vm.exception())
|
if (vm.exception())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
if (is<NewExpression>(*this)) {
|
|
||||||
if (result.is_object())
|
|
||||||
return result;
|
|
||||||
return new_object;
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -922,11 +922,16 @@ public:
|
||||||
virtual void dump(int indent) const override;
|
virtual void dump(int indent) const override;
|
||||||
virtual void generate_bytecode(Bytecode::Generator&) const override;
|
virtual void generate_bytecode(Bytecode::Generator&) const override;
|
||||||
|
|
||||||
private:
|
Expression const& callee() const { return m_callee; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void throw_type_error_for_callee(Interpreter&, GlobalObject&, Value callee_value, StringView call_type) const;
|
||||||
|
|
||||||
struct ThisAndCallee {
|
struct ThisAndCallee {
|
||||||
Value this_value;
|
Value this_value;
|
||||||
Value callee;
|
Value callee;
|
||||||
};
|
};
|
||||||
|
|
||||||
ThisAndCallee compute_this_and_callee(Interpreter&, GlobalObject&) const;
|
ThisAndCallee compute_this_and_callee(Interpreter&, GlobalObject&) const;
|
||||||
|
|
||||||
NonnullRefPtr<Expression> m_callee;
|
NonnullRefPtr<Expression> m_callee;
|
||||||
|
@ -940,6 +945,8 @@ public:
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||||
|
|
||||||
virtual bool is_new_expression() const override { return true; }
|
virtual bool is_new_expression() const override { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue