Quellcode durchsuchen

LibJS: Implement the object literal __proto__ property key special case

Idan Horowitz vor 3 Jahren
Ursprung
Commit
7ebb421ee9

+ 11 - 0
Userland/Libraries/LibJS/AST.cpp

@@ -2994,6 +2994,17 @@ Completion ObjectExpression::execute(Interpreter& interpreter, GlobalObject& glo
 
         auto value = TRY(property.value().execute(interpreter, global_object)).release_value();
 
+        // 8. If isProtoSetter is true, then
+        if (property.type() == ObjectProperty::Type::ProtoSetter) {
+            // a. If Type(propValue) is either Object or Null, then
+            if (value.is_object() || value.is_null()) {
+                // i. Perform ! object.[[SetPrototypeOf]](propValue).
+                MUST(object->internal_set_prototype_of(value.is_object() ? &value.as_object() : nullptr));
+            }
+            // b. Return unused.
+            continue;
+        }
+
         if (value.is_function() && property.is_method())
             static_cast<ECMAScriptFunctionObject&>(value.as_function()).set_home_object(object);
 

+ 1 - 0
Userland/Libraries/LibJS/AST.h

@@ -1648,6 +1648,7 @@ public:
         Getter,
         Setter,
         Spread,
+        ProtoSetter,
     };
 
     ObjectProperty(SourceRange source_range, NonnullRefPtr<Expression> key, RefPtr<Expression> value, Type property_type, bool is_method)

+ 4 - 0
Userland/Libraries/LibJS/Parser.cpp

@@ -1700,6 +1700,8 @@ NonnullRefPtr<ObjectExpression> Parser::parse_object_expression()
             property_key = parse_property_key();
         }
 
+        // 4. Else if propKey is the String value "__proto__" and if IsComputedPropertyKey of PropertyName is false, then
+        // a. Let isProtoSetter be true.
         bool is_proto = (type == TokenType::StringLiteral || type == TokenType::Identifier) && is<StringLiteral>(*property_key) && static_cast<StringLiteral const&>(*property_key).value() == "__proto__";
 
         if (property_type == ObjectProperty::Type::Getter || property_type == ObjectProperty::Type::Setter) {
@@ -1741,6 +1743,8 @@ NonnullRefPtr<ObjectExpression> Parser::parse_object_expression()
                     syntax_error("Property name '__proto__' must not appear more than once in object literal");
                 has_direct_proto_property = true;
             }
+            if (is_proto && property_type == ObjectProperty::Type::KeyValue)
+                property_type = ObjectProperty::Type::ProtoSetter;
             properties.append(create_ast_node<ObjectProperty>({ m_state.current_token.filename(), rule_start.position(), position() }, *property_key, parse_expression(2), property_type, false));
         } else if (property_key && property_value) {
             if (m_state.strict_mode && is<StringLiteral>(*property_key)) {

+ 6 - 0
Userland/Libraries/LibJS/Tests/object-expression-__proto__.js

@@ -0,0 +1,6 @@
+test("__proto__ property", () => {
+    expect(Object.getPrototypeOf({ __proto__: null })).toBeNull();
+    expect(Object.getPrototypeOf({ __proto__: Array.prototype })).toEqual(Array.prototype);
+    expect(Object.getPrototypeOf({ "__proto__": Array.prototype })).toEqual(Array.prototype); // prettier-ignore
+    expect(Object.getOwnPropertyNames({ __proto__: Array.prototype, test: 1 })).toEqual(["test"]);
+});