Parcourir la source

LibJS: Bring the `super` keyword in line with the spec

This patch implements spec-compliant runtime semantics for the following
constructs:

- super.property
- super[property]

The MakeSuperPropertyReference AO is added to support this. :^)
Andreas Kling il y a 4 ans
Parent
commit
1270df2

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

@@ -720,6 +720,43 @@ Reference Identifier::to_reference(Interpreter& interpreter, GlobalObject&) cons
 
 
 Reference MemberExpression::to_reference(Interpreter& interpreter, GlobalObject& global_object) const
 Reference MemberExpression::to_reference(Interpreter& interpreter, GlobalObject& global_object) const
 {
 {
+    // 13.3.7.1 Runtime Semantics: Evaluation
+    // SuperProperty : super [ Expression ]
+    // SuperProperty : super . IdentifierName
+    // https://tc39.es/ecma262/#sec-super-keyword-runtime-semantics-evaluation
+    if (is<SuperExpression>(object())) {
+        // 1. Let env be GetThisEnvironment().
+        auto& environment = get_this_environment(interpreter.vm());
+        // 2. Let actualThis be ? env.GetThisBinding().
+        auto actual_this = environment.get_this_binding(global_object);
+
+        StringOrSymbol property_key;
+
+        if (is_computed()) {
+            // SuperProperty : super [ Expression ]
+
+            // 3. Let propertyNameReference be the result of evaluating Expression.
+            // 4. Let propertyNameValue be ? GetValue(propertyNameReference).
+            auto property_name_value = m_property->execute(interpreter, global_object);
+            if (interpreter.exception())
+                return {};
+            // 5. Let propertyKey be ? ToPropertyKey(propertyNameValue).
+            property_key = property_name_value.to_property_key(global_object);
+        } else {
+            // SuperProperty : super . IdentifierName
+
+            // 3. Let propertyKey be StringValue of IdentifierName.
+            VERIFY(is<Identifier>(property()));
+            property_key = static_cast<Identifier const&>(property()).string();
+        }
+
+        // 6. If the code matched by this SuperProperty is strict mode code, let strict be true; else let strict be false.
+        bool strict = interpreter.vm().in_strict_mode();
+
+        // 7. Return ? MakeSuperPropertyReference(actualThis, propertyKey, strict).
+        return make_super_property_reference(global_object, actual_this, property_key, strict);
+    }
+
     auto object_value = m_object->execute(interpreter, global_object);
     auto object_value = m_object->execute(interpreter, global_object);
     if (interpreter.exception())
     if (interpreter.exception())
         return {};
         return {};

+ 20 - 0
Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp

@@ -25,6 +25,7 @@
 #include <LibJS/Runtime/ObjectEnvironment.h>
 #include <LibJS/Runtime/ObjectEnvironment.h>
 #include <LibJS/Runtime/PropertyName.h>
 #include <LibJS/Runtime/PropertyName.h>
 #include <LibJS/Runtime/ProxyObject.h>
 #include <LibJS/Runtime/ProxyObject.h>
+#include <LibJS/Runtime/Reference.h>
 
 
 namespace JS {
 namespace JS {
 
 
@@ -180,6 +181,25 @@ Object* get_super_constructor(VM& vm)
     return super_constructor;
     return super_constructor;
 }
 }
 
 
+// 13.3.7.3 MakeSuperPropertyReference ( actualThis, propertyKey, strict )
+Reference make_super_property_reference(GlobalObject& global_object, Value actual_this, StringOrSymbol const& property_key, bool strict)
+{
+    auto& vm = global_object.vm();
+    // 1. Let env be GetThisEnvironment().
+    auto& env = verify_cast<FunctionEnvironment>(get_this_environment(vm));
+    // 2. Assert: env.HasSuperBinding() is true.
+    VERIFY(env.has_super_binding());
+    // 3. Let baseValue be ? env.GetSuperBase().
+    auto base_value = env.get_super_base();
+    // 4. Let bv be ? RequireObjectCoercible(baseValue).
+    auto bv = require_object_coercible(global_object, base_value);
+    if (vm.exception())
+        return {};
+    // 5. Return the Reference Record { [[Base]]: bv, [[ReferencedName]]: propertyKey, [[Strict]]: strict, [[ThisValue]]: actualThis }.
+    // 6. NOTE: This returns a Super Reference Record.
+    return Reference { bv, property_key, actual_this, strict };
+}
+
 // 19.2.1.1 PerformEval ( x, callerRealm, strictCaller, direct ), https://tc39.es/ecma262/#sec-performeval
 // 19.2.1.1 PerformEval ( x, callerRealm, strictCaller, direct ), https://tc39.es/ecma262/#sec-performeval
 Value perform_eval(Value x, GlobalObject& caller_realm, CallerMode strict_caller, EvalMode direct)
 Value perform_eval(Value x, GlobalObject& caller_realm, CallerMode strict_caller, EvalMode direct)
 {
 {

+ 1 - 0
Userland/Libraries/LibJS/Runtime/AbstractOperations.h

@@ -18,6 +18,7 @@ DeclarativeEnvironment* new_declarative_environment(Environment&);
 ObjectEnvironment* new_object_environment(Object&, bool is_with_environment, Environment*);
 ObjectEnvironment* new_object_environment(Object&, bool is_with_environment, Environment*);
 Environment& get_this_environment(VM&);
 Environment& get_this_environment(VM&);
 Object* get_super_constructor(VM&);
 Object* get_super_constructor(VM&);
+Reference make_super_property_reference(GlobalObject&, Value actual_this, StringOrSymbol const& property_key, bool strict);
 Value require_object_coercible(GlobalObject&, Value);
 Value require_object_coercible(GlobalObject&, Value);
 size_t length_of_array_like(GlobalObject&, Object const&);
 size_t length_of_array_like(GlobalObject&, Object const&);
 MarkedValueList create_list_from_array_like(GlobalObject&, Value, Function<Result<void, ErrorType>(Value)> = {});
 MarkedValueList create_list_from_array_like(GlobalObject&, Value, Function<Result<void, ErrorType>(Value)> = {});