소스 검색

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.
Andreas Kling 5 년 전
부모
커밋
35aea2e454

+ 6 - 10
Libraries/LibJS/AST.cpp

@@ -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

+ 1 - 1
Libraries/LibJS/Interpreter.cpp

@@ -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()) {

+ 1 - 1
Libraries/LibJS/Interpreter.h

@@ -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*>&);

+ 4 - 4
Libraries/LibJS/Runtime/ErrorPrototype.cpp

@@ -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);

+ 4 - 4
Libraries/LibJS/Runtime/Function.cpp

@@ -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();

+ 8 - 4
Libraries/LibJS/Runtime/FunctionPrototype.cpp

@@ -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));
 }
 

+ 10 - 10
Libraries/LibJS/Runtime/Object.cpp

@@ -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()));

+ 4 - 4
Libraries/LibJS/Runtime/Object.h

@@ -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,

+ 7 - 2
Libraries/LibJS/Runtime/ObjectConstructor.cpp

@@ -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;

+ 1 - 1
Libraries/LibJS/Runtime/Uint8ClampedArray.cpp

@@ -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);

+ 1 - 1
Libraries/LibJS/Runtime/Uint8ClampedArray.h

@@ -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; }

+ 3 - 3
Libraries/LibJS/Runtime/Value.cpp

@@ -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)

+ 7 - 0
Libraries/LibJS/Runtime/Value.h

@@ -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 };
 

+ 3 - 3
Userland/js.cpp

@@ -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 {};