1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-22 15:55:07 +00:00

LibJS: Add Value::{is, as}_function()

This commit is contained in:
Linus Groh 2020-05-06 11:52:53 +01:00 committed by Andreas Kling
parent 419bce6915
commit eea62dd365
6 changed files with 26 additions and 15 deletions

View file

@ -114,8 +114,7 @@ Value CallExpression::execute(Interpreter& interpreter) const
ASSERT(!callee.is_empty()); ASSERT(!callee.is_empty());
if (!callee.is_object() if (!callee.is_function()
|| !callee.as_object().is_function()
|| (is_new_expression() && (callee.as_object().is_native_function() && !static_cast<NativeFunction&>(callee.as_object()).has_constructor()))) { || (is_new_expression() && (callee.as_object().is_native_function() && !static_cast<NativeFunction&>(callee.as_object()).has_constructor()))) {
String error_message; String error_message;
auto call_type = is_new_expression() ? "constructor" : "function"; auto call_type = is_new_expression() ? "constructor" : "function";
@ -132,7 +131,7 @@ Value CallExpression::execute(Interpreter& interpreter) const
return interpreter.throw_exception<TypeError>(error_message); return interpreter.throw_exception<TypeError>(error_message);
} }
auto& function = static_cast<Function&>(callee.as_object()); auto& function = callee.as_function();
MarkedValueList arguments(interpreter.heap()); MarkedValueList arguments(interpreter.heap());
arguments.values().append(function.bound_arguments()); arguments.values().append(function.bound_arguments());
@ -469,7 +468,7 @@ Value UnaryExpression::execute(Interpreter& interpreter) const
case Value::Type::String: case Value::Type::String:
return js_string(interpreter, "string"); return js_string(interpreter, "string");
case Value::Type::Object: case Value::Type::Object:
if (lhs_result.as_object().is_function()) if (lhs_result.is_function())
return js_string(interpreter, "function"); return js_string(interpreter, "function");
return js_string(interpreter, "object"); return js_string(interpreter, "object");
case Value::Type::Boolean: case Value::Type::Boolean:

View file

@ -76,11 +76,11 @@ static Function* callback_from_args(Interpreter& interpreter, const String& name
return nullptr; return nullptr;
} }
auto callback = interpreter.argument(0); auto callback = interpreter.argument(0);
if (!callback.is_object() || !callback.as_object().is_function()) { if (!callback.is_function()) {
interpreter.throw_exception<TypeError>(String::format("%s is not a function", callback.to_string().characters())); interpreter.throw_exception<TypeError>(String::format("%s is not a function", callback.to_string().characters()));
return nullptr; return nullptr;
} }
return static_cast<Function*>(&callback.as_object()); return &callback.as_function();
} }
Value ArrayPrototype::filter(Interpreter& interpreter) Value ArrayPrototype::filter(Interpreter& interpreter)

View file

@ -477,10 +477,8 @@ Value Object::to_primitive(PreferredType preferred_type) const
Value Object::to_string() const Value Object::to_string() const
{ {
auto to_string_property = get("toString"); auto to_string_property = get("toString");
if (!to_string_property.is_empty() if (!to_string_property.is_empty() && to_string_property.is_function()) {
&& to_string_property.is_object() auto& to_string_function = to_string_property.as_function();
&& to_string_property.as_object().is_function()) {
auto& to_string_function = static_cast<Function&>(to_string_property.as_object());
auto& interpreter = const_cast<Object*>(this)->interpreter(); auto& interpreter = const_cast<Object*>(this)->interpreter();
auto to_string_result = interpreter.call(to_string_function, const_cast<Object*>(this)); auto to_string_result = interpreter.call(to_string_function, const_cast<Object*>(this));
if (to_string_result.is_object()) if (to_string_result.is_object())

View file

@ -47,11 +47,11 @@ static Object* get_target_object_from(Interpreter& interpreter, const String& na
static Function* get_target_function_from(Interpreter& interpreter, const String& name) static Function* get_target_function_from(Interpreter& interpreter, const String& name)
{ {
auto target = interpreter.argument(0); auto target = interpreter.argument(0);
if (!target.is_object() || !target.as_object().is_function()) { if (!target.is_function()) {
interpreter.throw_exception<TypeError>(String::format("First argument of Reflect.%s() must be a function", name.characters())); interpreter.throw_exception<TypeError>(String::format("First argument of Reflect.%s() must be a function", name.characters()));
return nullptr; return nullptr;
} }
return static_cast<Function*>(&target.as_object()); return &target.as_function();
} }
static void prepare_arguments_list(Interpreter& interpreter, Value value, MarkedValueList* arguments) static void prepare_arguments_list(Interpreter& interpreter, Value value, MarkedValueList* arguments)
@ -121,13 +121,12 @@ Value ReflectObject::construct(Interpreter& interpreter)
auto* new_target = target; auto* new_target = target;
if (interpreter.argument_count() > 2) { if (interpreter.argument_count() > 2) {
auto new_target_value = interpreter.argument(2); auto new_target_value = interpreter.argument(2);
if (!new_target_value.is_object() if (!new_target_value.is_function()
|| !new_target_value.as_object().is_function()
|| (new_target_value.as_object().is_native_function() && !static_cast<NativeFunction&>(new_target_value.as_object()).has_constructor())) { || (new_target_value.as_object().is_native_function() && !static_cast<NativeFunction&>(new_target_value.as_object()).has_constructor())) {
interpreter.throw_exception<TypeError>("Optional third argument of Reflect.construct() must be a constructor"); interpreter.throw_exception<TypeError>("Optional third argument of Reflect.construct() must be a constructor");
return {}; return {};
} }
new_target = static_cast<Function*>(&new_target_value.as_object()); new_target = &new_target_value.as_function();
} }
return interpreter.construct(*target, *new_target, move(arguments)); return interpreter.construct(*target, *new_target, move(arguments));
} }

View file

@ -31,6 +31,7 @@
#include <LibJS/Runtime/Array.h> #include <LibJS/Runtime/Array.h>
#include <LibJS/Runtime/BooleanObject.h> #include <LibJS/Runtime/BooleanObject.h>
#include <LibJS/Runtime/Error.h> #include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/Function.h>
#include <LibJS/Runtime/NumberObject.h> #include <LibJS/Runtime/NumberObject.h>
#include <LibJS/Runtime/Object.h> #include <LibJS/Runtime/Object.h>
#include <LibJS/Runtime/PrimitiveString.h> #include <LibJS/Runtime/PrimitiveString.h>
@ -48,6 +49,17 @@ bool Value::is_array() const
return is_object() && as_object().is_array(); return is_object() && as_object().is_array();
} }
bool Value::is_function() const
{
return is_object() && as_object().is_function();
}
Function& Value::as_function()
{
ASSERT(is_function());
return static_cast<Function&>(as_object());
}
String Value::to_string() const String Value::to_string() const
{ {
if (is_boolean()) if (is_boolean())

View file

@ -54,6 +54,7 @@ public:
bool is_boolean() const { return m_type == Type::Boolean; } bool is_boolean() const { return m_type == Type::Boolean; }
bool is_cell() const { return is_string() || is_object(); } bool is_cell() const { return is_string() || is_object(); }
bool is_array() const; bool is_array() const;
bool is_function() const;
bool is_nan() const { return is_number() && __builtin_isnan(as_double()); } bool is_nan() const { return is_number() && __builtin_isnan(as_double()); }
bool is_infinity() const { return is_number() && __builtin_isinf(as_double()); } bool is_infinity() const { return is_number() && __builtin_isinf(as_double()); }
@ -157,6 +158,8 @@ public:
return m_value.as_cell; return m_value.as_cell;
} }
Function& as_function();
String to_string() const; String to_string() const;
bool to_boolean() const; bool to_boolean() const;
Value to_number() const; Value to_number() const;