diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp index 199567a5f64..f6a2910bb22 100644 --- a/Libraries/LibJS/AST.cpp +++ b/Libraries/LibJS/AST.cpp @@ -973,7 +973,12 @@ void ArrayExpression::dump(int indent) const { ASTNode::dump(indent); for (auto& element : m_elements) { - element.dump(indent + 1); + if (element) { + element->dump(indent + 1); + } else { + print_indent(indent + 1); + printf("\n"); + } } } @@ -981,9 +986,12 @@ Value ArrayExpression::execute(Interpreter& interpreter) const { auto* array = interpreter.heap().allocate(); 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); } return array; diff --git a/Libraries/LibJS/AST.h b/Libraries/LibJS/AST.h index a9ff48e94ec..660cd1dad50 100644 --- a/Libraries/LibJS/AST.h +++ b/Libraries/LibJS/AST.h @@ -681,12 +681,12 @@ private: class ArrayExpression : public Expression { public: - ArrayExpression(NonnullRefPtrVector elements) + ArrayExpression(Vector> elements) : m_elements(move(elements)) { } - const NonnullRefPtrVector& elements() const { return m_elements; } + const Vector>& elements() const { return m_elements; } virtual Value execute(Interpreter&) const override; virtual void dump(int indent) const override; @@ -694,7 +694,7 @@ public: private: virtual const char* class_name() const override { return "ArrayExpression"; } - NonnullRefPtrVector m_elements; + Vector> m_elements; }; class MemberExpression final : public Expression { diff --git a/Libraries/LibJS/Parser.cpp b/Libraries/LibJS/Parser.cpp index c04b189cc53..015e0e0d466 100644 --- a/Libraries/LibJS/Parser.cpp +++ b/Libraries/LibJS/Parser.cpp @@ -473,9 +473,12 @@ NonnullRefPtr Parser::parse_array_expression() { consume(TokenType::BracketOpen); - NonnullRefPtrVector elements; - while (match_expression()) { - elements.append(parse_expression(0)); + Vector> elements; + while (match_expression() || match(TokenType::Comma)) { + RefPtr expression; + if (match_expression()) + expression = parse_expression(0); + elements.append(expression); if (!match(TokenType::Comma)) break; consume(TokenType::Comma); diff --git a/Libraries/LibJS/Tests/array-basic.js b/Libraries/LibJS/Tests/array-basic.js index bfd1064da79..b39bcda1342 100644 --- a/Libraries/LibJS/Tests/array-basic.js +++ b/Libraries/LibJS/Tests/array-basic.js @@ -17,6 +17,29 @@ try { assert(a[3] === 7); 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"); } catch (e) { console.log("FAIL: " + e);