LibJS: Stop using Optional<Value> in favor of Value's empty state

JS::Value already has the empty state ({} or Value() gives you one.)
Use this instead of wrapping Value in Optional in some places.
I've also added Value::value_or(Value) so you can easily provide a
fallback value when one is not present.
This commit is contained in:
Andreas Kling 2020-04-25 18:43:34 +02:00
parent 5adf4901df
commit 35aea2e454
Notes: sideshowbarker 2024-07-19 07:17:54 +09:00
14 changed files with 60 additions and 48 deletions

View file

@ -136,8 +136,8 @@ Value CallExpression::execute(Interpreter& interpreter) const
if (is_new_expression()) {
new_object = Object::create_empty(interpreter, interpreter.global_object());
auto prototype = function.get("prototype");
if (prototype.has_value() && prototype.value().is_object())
new_object->set_prototype(&prototype.value().as_object());
if (prototype.is_object())
new_object->set_prototype(&prototype.as_object());
call_frame.this_value = new_object;
result = function.construct(interpreter);
} else {
@ -704,10 +704,10 @@ void ForStatement::dump(int indent) const
Value Identifier::execute(Interpreter& interpreter) const
{
auto variable = interpreter.get_variable(string());
if (!variable.has_value())
auto value = interpreter.get_variable(string());
if (value.is_empty())
return interpreter.throw_exception<ReferenceError>(String::format("'%s' not known", string().characters()));
return variable.value();
return value;
}
void Identifier::dump(int indent) const
@ -1022,11 +1022,7 @@ Value MemberExpression::execute(Interpreter& interpreter) const
auto* object_result = object_value.to_object(interpreter.heap());
if (interpreter.exception())
return {};
auto result = object_result->get(computed_property_name(interpreter));
if (result.has_value()) {
ASSERT(!result.value().is_empty());
}
return result.value_or(js_undefined());
return object_result->get(computed_property_name(interpreter)).value_or(js_undefined());
}
Value StringLiteral::execute(Interpreter& interpreter) const

View file

@ -151,7 +151,7 @@ void Interpreter::set_variable(const FlyString& name, Value value, bool first_as
global_object().put(move(name), move(value));
}
Optional<Value> Interpreter::get_variable(const FlyString& name)
Value Interpreter::get_variable(const FlyString& name)
{
if (m_call_stack.size()) {
for (auto* environment = current_environment(); environment; environment = environment->parent()) {

View file

@ -93,7 +93,7 @@ public:
bool should_unwind_until(ScopeType type) const { return m_unwind_until == type; }
bool should_unwind() const { return m_unwind_until != ScopeType::None; }
Optional<Value> get_variable(const FlyString& name);
Value get_variable(const FlyString& name);
void set_variable(const FlyString& name, Value, bool first_assignment = false);
void gather_roots(Badge<Heap>, HashTable<Cell*>&);

View file

@ -88,13 +88,13 @@ Value ErrorPrototype::to_string(Interpreter& interpreter)
String name = "Error";
auto object_name_property = this_object.get("name");
if (object_name_property.has_value() && !object_name_property.value().is_undefined())
name = object_name_property.value().to_string();
if (!object_name_property.is_empty() && !object_name_property.is_undefined())
name = object_name_property.to_string();
String message = "";
auto object_message_property = this_object.get("message");
if (object_message_property.has_value() && !object_message_property.value().is_undefined())
message = object_message_property.value().to_string();
if (!object_message_property.is_empty() && !object_message_property.is_undefined())
message = object_message_property.to_string();
if (name.length() == 0)
return js_string(interpreter, message);

View file

@ -68,8 +68,8 @@ BoundFunction* Function::bind(Value bound_this_value, Vector<Value> arguments)
if (interpreter().exception()) {
return nullptr;
}
if (length_property.has_value() && length_property.value().is_number()) {
computed_length = max(0, length_property.value().to_i32() - static_cast<i32>(arguments.size()));
if (length_property.is_number()) {
computed_length = max(0, length_property.to_i32() - static_cast<i32>(arguments.size()));
}
Object* constructor_prototype = nullptr;
@ -77,8 +77,8 @@ BoundFunction* Function::bind(Value bound_this_value, Vector<Value> arguments)
if (interpreter().exception()) {
return nullptr;
}
if (prototype_property.has_value() && prototype_property.value().is_object()) {
constructor_prototype = &prototype_property.value().as_object();
if (prototype_property.is_object()) {
constructor_prototype = &prototype_property.as_object();
}
auto all_bound_arguments = bound_arguments();

View file

@ -72,11 +72,15 @@ Value FunctionPrototype::apply(Interpreter& interpreter)
return interpreter.throw_exception<TypeError>("argument array must be an object");
size_t length = 0;
auto length_property = arg_array.as_object().get("length");
if (length_property.has_value())
length = length_property.value().to_number().to_i32();
if (!length_property.is_empty())
length = length_property.to_number().to_i32();
MarkedValueList arguments(interpreter.heap());
for (size_t i = 0; i < length; ++i)
arguments.append(arg_array.as_object().get(String::number(i)).value_or(js_undefined()));
for (size_t i = 0; i < length; ++i) {
auto element = arg_array.as_object().get(String::number(i));
if (interpreter.exception())
return {};
arguments.append(element.value_or(js_undefined()));
}
return interpreter.call(function, this_arg, move(arguments));
}

View file

@ -83,7 +83,7 @@ bool Object::has_prototype(const Object* prototype) const
return false;
}
Optional<Value> Object::get_own_property(const Object& this_object, const FlyString& property_name) const
Value Object::get_own_property(const Object& this_object, const FlyString& property_name) const
{
auto metadata = shape().lookup(property_name);
if (!metadata.has_value())
@ -154,7 +154,7 @@ void Object::put_own_property(Object& this_object, const FlyString& property_nam
}
}
Optional<Value> Object::get_by_index(i32 property_index) const
Value Object::get_by_index(i32 property_index) const
{
if (property_index < 0)
return get(String::number(property_index));
@ -172,7 +172,7 @@ Optional<Value> Object::get_by_index(i32 property_index) const
return {};
}
Optional<Value> Object::get(const FlyString& property_name) const
Value Object::get(const FlyString& property_name) const
{
bool ok;
i32 property_index = property_name.to_int(ok);
@ -182,14 +182,14 @@ Optional<Value> Object::get(const FlyString& property_name) const
const Object* object = this;
while (object) {
auto value = object->get_own_property(*this, property_name);
if (value.has_value())
return value.value();
if (!value.is_empty())
return value;
object = object->prototype();
}
return {};
}
Optional<Value> Object::get(PropertyName property_name) const
Value Object::get(PropertyName property_name) const
{
if (property_name.is_number())
return get_by_index(property_name.as_number());
@ -308,10 +308,10 @@ Value Object::to_primitive(PreferredType preferred_type) const
Value Object::to_string() const
{
auto to_string_property = get("toString");
if (to_string_property.has_value()
&& to_string_property.value().is_object()
&& to_string_property.value().as_object().is_function()) {
auto& to_string_function = static_cast<Function&>(to_string_property.value().as_object());
if (!to_string_property.is_empty()
&& to_string_property.is_object()
&& to_string_property.as_object().is_function()) {
auto& to_string_function = static_cast<Function&>(to_string_property.as_object());
return const_cast<Object*>(this)->interpreter().call(&to_string_function, const_cast<Object*>(this));
}
return js_string(heap(), String::format("[object %s]", class_name()));

View file

@ -46,15 +46,15 @@ public:
Shape& shape() { return *m_shape; }
const Shape& shape() const { return *m_shape; }
virtual Optional<Value> get_by_index(i32 property_index) const;
Optional<Value> get(const FlyString& property_name) const;
Optional<Value> get(PropertyName) const;
virtual Value get_by_index(i32 property_index) const;
Value get(const FlyString& property_name) const;
Value get(PropertyName) const;
virtual void put_by_index(i32 property_index, Value);
void put(const FlyString& property_name, Value);
void put(PropertyName, Value);
Optional<Value> get_own_property(const Object& this_object, const FlyString& property_name) const;
Value get_own_property(const Object& this_object, const FlyString& property_name) const;
enum class PutOwnPropertyMode {
Put,

View file

@ -110,11 +110,16 @@ Value ObjectConstructor::get_own_property_descriptor(Interpreter& interpreter)
auto metadata = object.shape().lookup(interpreter.argument(1).to_string());
if (!metadata.has_value())
return js_undefined();
auto value = object.get(interpreter.argument(1).to_string()).value_or(js_undefined());
if (interpreter.exception())
return {};
auto* descriptor = Object::create_empty(interpreter, interpreter.global_object());
descriptor->put("configurable", Value(!!(metadata.value().attributes & Attribute::Configurable)));
descriptor->put("enumerable", Value(!!(metadata.value().attributes & Attribute::Enumerable)));
descriptor->put("writable", Value(!!(metadata.value().attributes & Attribute::Writable)));
descriptor->put("value", object.get(interpreter.argument(1).to_string()).value_or(js_undefined()));
descriptor->put("value", value);
return descriptor;
}
@ -129,7 +134,7 @@ Value ObjectConstructor::define_property(Interpreter& interpreter)
auto& object = interpreter.argument(0).as_object();
auto& descriptor = interpreter.argument(2).as_object();
Value value = descriptor.get("value").value_or(Value());
auto value = descriptor.get("value");
u8 configurable = descriptor.get("configurable").value_or(Value(false)).to_boolean() * Attribute::Configurable;
u8 enumerable = descriptor.get("enumerable").value_or(Value(false)).to_boolean() * Attribute::Enumerable;
u8 writable = descriptor.get("writable").value_or(Value(false)).to_boolean() * Attribute::Writable;

View file

@ -72,7 +72,7 @@ void Uint8ClampedArray::put_by_index(i32 property_index, Value value)
m_data[property_index] = clamp(value.to_i32(), 0, 255);
}
Optional<Value> Uint8ClampedArray::get_by_index(i32 property_index) const
Value Uint8ClampedArray::get_by_index(i32 property_index) const
{
ASSERT(property_index >= 0);
ASSERT(property_index < m_length);

View file

@ -40,7 +40,7 @@ public:
i32 length() const { return m_length; }
virtual void put_by_index(i32 property_index, Value value) override;
virtual Optional<Value> get_by_index(i32 property_index) const override;
virtual Value get_by_index(i32 property_index) const override;
u8* data() { return m_data; }
const u8* data() const { return m_data; }

View file

@ -387,7 +387,7 @@ Value in(Interpreter& interpreter, Value lhs, Value rhs)
if (!rhs.is_object())
return interpreter.throw_exception<TypeError>("'in' operator must be used on object");
return Value(rhs.as_object().get(lhs.to_string()).has_value());
return Value(!rhs.as_object().get(lhs.to_string()).is_empty());
}
Value instance_of(Interpreter&, Value lhs, Value rhs)
@ -396,10 +396,10 @@ Value instance_of(Interpreter&, Value lhs, Value rhs)
return Value(false);
auto constructor_prototype_property = rhs.as_object().get("prototype");
if (!constructor_prototype_property.has_value() || !constructor_prototype_property.value().is_object())
if (!constructor_prototype_property.is_object())
return Value(false);
return Value(lhs.as_object().has_prototype(&constructor_prototype_property.value().as_object()));
return Value(lhs.as_object().has_prototype(&constructor_prototype_property.as_object()));
}
const LogStream& operator<<(const LogStream& stream, const Value& value)

View file

@ -164,6 +164,13 @@ public:
Object* to_object(Heap&) const;
Value value_or(Value fallback) const
{
if (is_empty())
return fallback;
return *this;
}
private:
Type m_type { Type::Empty };

View file

@ -607,13 +607,13 @@ int main(int argc, char** argv)
auto property_pattern = parts[1];
auto maybe_variable = interpreter->get_variable(name);
if (!maybe_variable.has_value()) {
if (maybe_variable.is_empty()) {
maybe_variable = interpreter->global_object().get(name);
if (!maybe_variable.has_value())
if (maybe_variable.is_empty())
return {};
}
const auto& variable = maybe_variable.value();
auto variable = maybe_variable;
if (!variable.is_object())
return {};