Ver Fonte

LibJS: Make typeof return undefined for undefined variables

This makes `typeof i_dont_exist` return `undefined` instead of 
throwing an error.
Marcin Gasperowicz há 5 anos atrás
pai
commit
0b74ea3d6a
2 ficheiros alterados com 32 adições e 3 exclusões
  1. 19 3
      Libraries/LibJS/AST.cpp
  2. 13 0
      Libraries/LibJS/Tests/typeof-basic.js

+ 19 - 3
Libraries/LibJS/AST.cpp

@@ -585,9 +585,25 @@ Value UnaryExpression::execute(Interpreter& interpreter) const
         return base_object->delete_property(reference.name());
         return base_object->delete_property(reference.name());
     }
     }
 
 
-    auto lhs_result = m_lhs->execute(interpreter);
-    if (interpreter.exception())
-        return {};
+    Value lhs_result;
+    if (m_op == UnaryOp::Typeof && m_lhs->is_identifier()) {
+        auto reference = m_lhs->to_reference(interpreter);
+        if (interpreter.exception()) {
+            return {};
+        }
+        // FIXME: standard recommends checking with is_unresolvable but it ALWAYS return false here
+        if (reference.is_local_variable() || reference.is_global_variable()) {
+            auto name = reference.name();
+            lhs_result = interpreter.get_variable(name.to_string()).value_or(js_undefined());
+            if (interpreter.exception())
+                return {};
+        }
+    } else {
+        lhs_result = m_lhs->execute(interpreter);
+        if (interpreter.exception())
+            return {};
+    }
+
     switch (m_op) {
     switch (m_op) {
     case UnaryOp::BitwiseNot:
     case UnaryOp::BitwiseNot:
         return bitwise_not(interpreter, lhs_result);
         return bitwise_not(interpreter, lhs_result);

+ 13 - 0
Libraries/LibJS/Tests/typeof-basic.js

@@ -8,6 +8,19 @@ try {
     assert(typeof null === "object");
     assert(typeof null === "object");
     assert(typeof undefined === "undefined");
     assert(typeof undefined === "undefined");
 
 
+    var iExist = 1;
+    assert(typeof iExist === "number");
+    assert(typeof iDontExist === "undefined");
+
+    var calls = 0;
+    Object.defineProperty(globalThis, "foo", {
+        get() {
+            calls++;
+        },
+    });
+    assert(typeof foo === "undefined");
+    assert(calls === 1);
+
     console.log("PASS");
     console.log("PASS");
 } catch (e) {
 } catch (e) {
     console.log("FAIL: " + e);
     console.log("FAIL: " + e);