diff --git a/Libraries/LibJS/Parser.cpp b/Libraries/LibJS/Parser.cpp index 454c94922a..d7cb24a16a 100644 --- a/Libraries/LibJS/Parser.cpp +++ b/Libraries/LibJS/Parser.cpp @@ -299,7 +299,7 @@ RefPtr Parser::try_parse_arrow_function_expression(bool expe if (expect_parens && match(TokenType::Equals)) { consume(TokenType::Equals); function_length = parameters.size(); - default_value = parse_expression(0); + default_value = parse_expression(2); } parameters.append({ parameter_name, default_value }); } else if (match(TokenType::TripleDot)) { @@ -340,7 +340,7 @@ RefPtr Parser::try_parse_arrow_function_expression(bool expe if (parse_failed) return nullptr; - if (function_length == -1) + if (function_length == -1) function_length = parameters.size(); auto function_body_result = [this]() -> RefPtr { @@ -504,7 +504,7 @@ NonnullRefPtr Parser::parse_object_expression() consume(TokenType::BracketClose); } else if (match(TokenType::TripleDot)) { consume(TokenType::TripleDot); - property_key = create_ast_node(parse_expression(0)); + property_key = create_ast_node(parse_expression(2)); property_value = property_key; need_colon = false; is_spread = true; @@ -518,7 +518,7 @@ NonnullRefPtr Parser::parse_object_expression() property_value = parse_function_node(false); } else if (need_colon || match(TokenType::Colon)) { consume(TokenType::Colon); - property_value = parse_expression(0); + property_value = parse_expression(2); } auto property = create_ast_node(*property_key, *property_value); properties.append(property); @@ -545,9 +545,9 @@ NonnullRefPtr Parser::parse_array_expression() if (match(TokenType::TripleDot)) { consume(TokenType::TripleDot); - expression = create_ast_node(parse_expression(0)); + expression = create_ast_node(parse_expression(2)); } else if (match_expression()) { - expression = parse_expression(0); + expression = parse_expression(2); } elements.append(expression); @@ -634,6 +634,15 @@ NonnullRefPtr Parser::parse_expression(int min_precedence, Associati expression = create_ast_node(move(expression), move(template_literal)); } } + if (match(TokenType::Comma) && min_precedence <= 1) { + NonnullRefPtrVector expressions; + expressions.append(expression); + while (match(TokenType::Comma)) { + consume(); + expressions.append(parse_expression(2)); + } + expression = create_ast_node(move(expressions)); + } return expression; } @@ -795,9 +804,9 @@ NonnullRefPtr Parser::parse_call_expression(NonnullRefPtr Parser::parse_new_expression() while (match_expression() || match(TokenType::TripleDot)) { if (match(TokenType::TripleDot)) { consume(); - arguments.append({ parse_expression(0), true }); + arguments.append({ parse_expression(2), true }); } else { - arguments.append({ parse_expression(0), false }); + arguments.append({ parse_expression(2), false }); } if (!match(TokenType::Comma)) break; @@ -906,7 +915,7 @@ NonnullRefPtr Parser::parse_function_node(bool needs_function_ if (match(TokenType::Equals)) { consume(TokenType::Equals); function_length = parameters.size(); - default_value = parse_expression(0); + default_value = parse_expression(2); } parameters.append({ parameter_name, default_value }); if (match(TokenType::ParenClose)) @@ -917,7 +926,7 @@ NonnullRefPtr Parser::parse_function_node(bool needs_function_ if (function_length == -1) function_length = parameters.size(); - + auto body = parse_block_statement(); body->add_variables(m_parser_state.m_var_scopes.last()); return create_ast_node(name, move(body), move(parameters), function_length, NonnullRefPtrVector()); @@ -950,7 +959,7 @@ NonnullRefPtr Parser::parse_variable_declaration() RefPtr init; if (match(TokenType::Equals)) { consume(); - init = parse_expression(0); + init = parse_expression(2); } declarations.append(create_ast_node(create_ast_node(move(id)), move(init))); if (match(TokenType::Comma)) { diff --git a/Libraries/LibJS/Tests/comma-operator.js b/Libraries/LibJS/Tests/comma-operator.js new file mode 100644 index 0000000000..8f8c65a532 --- /dev/null +++ b/Libraries/LibJS/Tests/comma-operator.js @@ -0,0 +1,26 @@ +load("test-common.js"); + +try { + assert((1, 2, 3) === 3); + assert((1, 2 + 3, 4) === 4); + + var foo = 0; + foo = (foo++, foo); + assert(foo === 1); + + var a, b, c; + assert((a = b = 3, c = 4) === 4); + assert(a === 3); + assert(b === 3); + assert(c === 4); + + var x, y, z; + assert((x = (y = 5, z = 6)) === 6); + assert(x === 6) + assert(y === 5) + assert(z === 6) + + console.log("PASS"); +} catch (e) { + console.log("FAIL: " + e); +}