Forráskód Böngészése

LibJS: Support empty values in array expression

Linus Groh 5 éve
szülő
commit
cea950fd70

+ 12 - 4
Libraries/LibJS/AST.cpp

@@ -973,7 +973,12 @@ void ArrayExpression::dump(int indent) const
 {
 {
     ASTNode::dump(indent);
     ASTNode::dump(indent);
     for (auto& element : m_elements) {
     for (auto& element : m_elements) {
-        element.dump(indent + 1);
+        if (element) {
+            element->dump(indent + 1);
+        } else {
+            print_indent(indent + 1);
+            printf("<empty>\n");
+        }
     }
     }
 }
 }
 
 
@@ -981,9 +986,12 @@ Value ArrayExpression::execute(Interpreter& interpreter) const
 {
 {
     auto* array = interpreter.heap().allocate<Array>();
     auto* array = interpreter.heap().allocate<Array>();
     for (auto& element : m_elements) {
     for (auto& element : m_elements) {
-        auto value = element.execute(interpreter);
-        if (interpreter.exception())
-            return {};
+        auto value = Value();
+        if (element) {
+            value = element->execute(interpreter);
+            if (interpreter.exception())
+                return {};
+        }
         array->elements().append(value);
         array->elements().append(value);
     }
     }
     return array;
     return array;

+ 3 - 3
Libraries/LibJS/AST.h

@@ -681,12 +681,12 @@ private:
 
 
 class ArrayExpression : public Expression {
 class ArrayExpression : public Expression {
 public:
 public:
-    ArrayExpression(NonnullRefPtrVector<Expression> elements)
+    ArrayExpression(Vector<RefPtr<Expression>> elements)
         : m_elements(move(elements))
         : m_elements(move(elements))
     {
     {
     }
     }
 
 
-    const NonnullRefPtrVector<Expression>& elements() const { return m_elements; }
+    const Vector<RefPtr<Expression>>& elements() const { return m_elements; }
 
 
     virtual Value execute(Interpreter&) const override;
     virtual Value execute(Interpreter&) const override;
     virtual void dump(int indent) const override;
     virtual void dump(int indent) const override;
@@ -694,7 +694,7 @@ public:
 private:
 private:
     virtual const char* class_name() const override { return "ArrayExpression"; }
     virtual const char* class_name() const override { return "ArrayExpression"; }
 
 
-    NonnullRefPtrVector<Expression> m_elements;
+    Vector<RefPtr<Expression>> m_elements;
 };
 };
 
 
 class MemberExpression final : public Expression {
 class MemberExpression final : public Expression {

+ 6 - 3
Libraries/LibJS/Parser.cpp

@@ -473,9 +473,12 @@ NonnullRefPtr<ArrayExpression> Parser::parse_array_expression()
 {
 {
     consume(TokenType::BracketOpen);
     consume(TokenType::BracketOpen);
 
 
-    NonnullRefPtrVector<Expression> elements;
-    while (match_expression()) {
-        elements.append(parse_expression(0));
+    Vector<RefPtr<Expression>> elements;
+    while (match_expression() || match(TokenType::Comma)) {
+        RefPtr<Expression> expression;
+        if (match_expression())
+            expression = parse_expression(0);
+        elements.append(expression);
         if (!match(TokenType::Comma))
         if (!match(TokenType::Comma))
             break;
             break;
         consume(TokenType::Comma);
         consume(TokenType::Comma);

+ 23 - 0
Libraries/LibJS/Tests/array-basic.js

@@ -17,6 +17,29 @@ try {
     assert(a[3] === 7);
     assert(a[3] === 7);
     assert(a.length === 4);
     assert(a.length === 4);
 
 
+    a = [,];
+    assert(a.length === 1);
+    assert(a.toString() === "");
+    assert(a[0] === undefined);
+
+    a = [,,,,];
+    assert(a.length === 4);
+    assert(a.toString() === ",,,");
+    assert(a[0] === undefined);
+    assert(a[1] === undefined);
+    assert(a[2] === undefined);
+    assert(a[3] === undefined);
+
+    a = [1,,2,,,3,];
+    assert(a.length === 6);
+    assert(a.toString() === "1,,2,,,3");
+    assert(a[0] === 1);
+    assert(a[1] === undefined);
+    assert(a[2] === 2);
+    assert(a[3] === undefined);
+    assert(a[4] === undefined);
+    assert(a[5] === 3);
+
     console.log("PASS");
     console.log("PASS");
 } catch (e) {
 } catch (e) {
     console.log("FAIL: " + e);
     console.log("FAIL: " + e);