mirror of
https://github.com/RGBCube/serenity
synced 2025-07-23 04:17:34 +00:00
LibJS: Fix cases where we incorrectly allowed 'in' in for loops
We needed to propagate the forbidden token set to all parsing functions that can call back into parse_expression.
This commit is contained in:
parent
5da3063a39
commit
f55d7bf6f3
3 changed files with 69 additions and 50 deletions
|
@ -1922,7 +1922,7 @@ NonnullRefPtr<Expression> Parser::parse_expression(int min_precedence, Associati
|
|||
check_for_invalid_object_property(expression);
|
||||
|
||||
Associativity new_associativity = operator_associativity(m_state.current_token.type());
|
||||
expression = parse_secondary_expression(move(expression), new_precedence, new_associativity);
|
||||
expression = parse_secondary_expression(move(expression), new_precedence, new_associativity, forbidden);
|
||||
while (match(TokenType::TemplateLiteralStart) && !is<UpdateExpression>(*expression)) {
|
||||
auto template_literal = parse_template_literal(true);
|
||||
expression = create_ast_node<TaggedTemplateLiteral>({ m_state.current_token.filename(), rule_start.position(), position() }, move(expression), move(template_literal));
|
||||
|
@ -1965,104 +1965,104 @@ NonnullRefPtr<Expression> Parser::parse_expression(int min_precedence, Associati
|
|||
return expression;
|
||||
}
|
||||
|
||||
NonnullRefPtr<Expression> Parser::parse_secondary_expression(NonnullRefPtr<Expression> lhs, int min_precedence, Associativity associativity)
|
||||
NonnullRefPtr<Expression> Parser::parse_secondary_expression(NonnullRefPtr<Expression> lhs, int min_precedence, Associativity associativity, Vector<TokenType> const& forbidden)
|
||||
{
|
||||
auto rule_start = push_start();
|
||||
switch (m_state.current_token.type()) {
|
||||
case TokenType::Plus:
|
||||
consume();
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::Addition, move(lhs), parse_expression(min_precedence, associativity));
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::Addition, move(lhs), parse_expression(min_precedence, associativity, forbidden));
|
||||
case TokenType::PlusEquals:
|
||||
return parse_assignment_expression(AssignmentOp::AdditionAssignment, move(lhs), min_precedence, associativity);
|
||||
return parse_assignment_expression(AssignmentOp::AdditionAssignment, move(lhs), min_precedence, associativity, forbidden);
|
||||
case TokenType::Minus:
|
||||
consume();
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::Subtraction, move(lhs), parse_expression(min_precedence, associativity));
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::Subtraction, move(lhs), parse_expression(min_precedence, associativity, forbidden));
|
||||
case TokenType::MinusEquals:
|
||||
return parse_assignment_expression(AssignmentOp::SubtractionAssignment, move(lhs), min_precedence, associativity);
|
||||
return parse_assignment_expression(AssignmentOp::SubtractionAssignment, move(lhs), min_precedence, associativity, forbidden);
|
||||
case TokenType::Asterisk:
|
||||
consume();
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::Multiplication, move(lhs), parse_expression(min_precedence, associativity));
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::Multiplication, move(lhs), parse_expression(min_precedence, associativity, forbidden));
|
||||
case TokenType::AsteriskEquals:
|
||||
return parse_assignment_expression(AssignmentOp::MultiplicationAssignment, move(lhs), min_precedence, associativity);
|
||||
return parse_assignment_expression(AssignmentOp::MultiplicationAssignment, move(lhs), min_precedence, associativity, forbidden);
|
||||
case TokenType::Slash:
|
||||
consume();
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::Division, move(lhs), parse_expression(min_precedence, associativity));
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::Division, move(lhs), parse_expression(min_precedence, associativity, forbidden));
|
||||
case TokenType::SlashEquals:
|
||||
return parse_assignment_expression(AssignmentOp::DivisionAssignment, move(lhs), min_precedence, associativity);
|
||||
return parse_assignment_expression(AssignmentOp::DivisionAssignment, move(lhs), min_precedence, associativity, forbidden);
|
||||
case TokenType::Percent:
|
||||
consume();
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::Modulo, move(lhs), parse_expression(min_precedence, associativity));
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::Modulo, move(lhs), parse_expression(min_precedence, associativity, forbidden));
|
||||
case TokenType::PercentEquals:
|
||||
return parse_assignment_expression(AssignmentOp::ModuloAssignment, move(lhs), min_precedence, associativity);
|
||||
return parse_assignment_expression(AssignmentOp::ModuloAssignment, move(lhs), min_precedence, associativity, forbidden);
|
||||
case TokenType::DoubleAsterisk:
|
||||
consume();
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::Exponentiation, move(lhs), parse_expression(min_precedence, associativity));
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::Exponentiation, move(lhs), parse_expression(min_precedence, associativity, forbidden));
|
||||
case TokenType::DoubleAsteriskEquals:
|
||||
return parse_assignment_expression(AssignmentOp::ExponentiationAssignment, move(lhs), min_precedence, associativity);
|
||||
return parse_assignment_expression(AssignmentOp::ExponentiationAssignment, move(lhs), min_precedence, associativity, forbidden);
|
||||
case TokenType::GreaterThan:
|
||||
consume();
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::GreaterThan, move(lhs), parse_expression(min_precedence, associativity));
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::GreaterThan, move(lhs), parse_expression(min_precedence, associativity, forbidden));
|
||||
case TokenType::GreaterThanEquals:
|
||||
consume();
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::GreaterThanEquals, move(lhs), parse_expression(min_precedence, associativity));
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::GreaterThanEquals, move(lhs), parse_expression(min_precedence, associativity, forbidden));
|
||||
case TokenType::LessThan:
|
||||
consume();
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::LessThan, move(lhs), parse_expression(min_precedence, associativity));
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::LessThan, move(lhs), parse_expression(min_precedence, associativity, forbidden));
|
||||
case TokenType::LessThanEquals:
|
||||
consume();
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::LessThanEquals, move(lhs), parse_expression(min_precedence, associativity));
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::LessThanEquals, move(lhs), parse_expression(min_precedence, associativity, forbidden));
|
||||
case TokenType::EqualsEqualsEquals:
|
||||
consume();
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::StrictlyEquals, move(lhs), parse_expression(min_precedence, associativity));
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::StrictlyEquals, move(lhs), parse_expression(min_precedence, associativity, forbidden));
|
||||
case TokenType::ExclamationMarkEqualsEquals:
|
||||
consume();
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::StrictlyInequals, move(lhs), parse_expression(min_precedence, associativity));
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::StrictlyInequals, move(lhs), parse_expression(min_precedence, associativity, forbidden));
|
||||
case TokenType::EqualsEquals:
|
||||
consume();
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::LooselyEquals, move(lhs), parse_expression(min_precedence, associativity));
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::LooselyEquals, move(lhs), parse_expression(min_precedence, associativity, forbidden));
|
||||
case TokenType::ExclamationMarkEquals:
|
||||
consume();
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::LooselyInequals, move(lhs), parse_expression(min_precedence, associativity));
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::LooselyInequals, move(lhs), parse_expression(min_precedence, associativity, forbidden));
|
||||
case TokenType::In:
|
||||
consume();
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::In, move(lhs), parse_expression(min_precedence, associativity));
|
||||
case TokenType::Instanceof:
|
||||
consume();
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::InstanceOf, move(lhs), parse_expression(min_precedence, associativity));
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::InstanceOf, move(lhs), parse_expression(min_precedence, associativity, forbidden));
|
||||
case TokenType::Ampersand:
|
||||
consume();
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::BitwiseAnd, move(lhs), parse_expression(min_precedence, associativity));
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::BitwiseAnd, move(lhs), parse_expression(min_precedence, associativity, forbidden));
|
||||
case TokenType::AmpersandEquals:
|
||||
return parse_assignment_expression(AssignmentOp::BitwiseAndAssignment, move(lhs), min_precedence, associativity);
|
||||
return parse_assignment_expression(AssignmentOp::BitwiseAndAssignment, move(lhs), min_precedence, associativity, forbidden);
|
||||
case TokenType::Pipe:
|
||||
consume();
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::BitwiseOr, move(lhs), parse_expression(min_precedence, associativity));
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::BitwiseOr, move(lhs), parse_expression(min_precedence, associativity, forbidden));
|
||||
case TokenType::PipeEquals:
|
||||
return parse_assignment_expression(AssignmentOp::BitwiseOrAssignment, move(lhs), min_precedence, associativity);
|
||||
return parse_assignment_expression(AssignmentOp::BitwiseOrAssignment, move(lhs), min_precedence, associativity, forbidden);
|
||||
case TokenType::Caret:
|
||||
consume();
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::BitwiseXor, move(lhs), parse_expression(min_precedence, associativity));
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::BitwiseXor, move(lhs), parse_expression(min_precedence, associativity, forbidden));
|
||||
case TokenType::CaretEquals:
|
||||
return parse_assignment_expression(AssignmentOp::BitwiseXorAssignment, move(lhs), min_precedence, associativity);
|
||||
return parse_assignment_expression(AssignmentOp::BitwiseXorAssignment, move(lhs), min_precedence, associativity, forbidden);
|
||||
case TokenType::ShiftLeft:
|
||||
consume();
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::LeftShift, move(lhs), parse_expression(min_precedence, associativity));
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::LeftShift, move(lhs), parse_expression(min_precedence, associativity, forbidden));
|
||||
case TokenType::ShiftLeftEquals:
|
||||
return parse_assignment_expression(AssignmentOp::LeftShiftAssignment, move(lhs), min_precedence, associativity);
|
||||
return parse_assignment_expression(AssignmentOp::LeftShiftAssignment, move(lhs), min_precedence, associativity, forbidden);
|
||||
case TokenType::ShiftRight:
|
||||
consume();
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::RightShift, move(lhs), parse_expression(min_precedence, associativity));
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::RightShift, move(lhs), parse_expression(min_precedence, associativity, forbidden));
|
||||
case TokenType::ShiftRightEquals:
|
||||
return parse_assignment_expression(AssignmentOp::RightShiftAssignment, move(lhs), min_precedence, associativity);
|
||||
return parse_assignment_expression(AssignmentOp::RightShiftAssignment, move(lhs), min_precedence, associativity, forbidden);
|
||||
case TokenType::UnsignedShiftRight:
|
||||
consume();
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::UnsignedRightShift, move(lhs), parse_expression(min_precedence, associativity));
|
||||
return create_ast_node<BinaryExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, BinaryOp::UnsignedRightShift, move(lhs), parse_expression(min_precedence, associativity, forbidden));
|
||||
case TokenType::UnsignedShiftRightEquals:
|
||||
return parse_assignment_expression(AssignmentOp::UnsignedRightShiftAssignment, move(lhs), min_precedence, associativity);
|
||||
return parse_assignment_expression(AssignmentOp::UnsignedRightShiftAssignment, move(lhs), min_precedence, associativity, forbidden);
|
||||
case TokenType::ParenOpen:
|
||||
return parse_call_expression(move(lhs));
|
||||
case TokenType::Equals:
|
||||
return parse_assignment_expression(AssignmentOp::Assignment, move(lhs), min_precedence, associativity);
|
||||
return parse_assignment_expression(AssignmentOp::Assignment, move(lhs), min_precedence, associativity, forbidden);
|
||||
case TokenType::Period:
|
||||
consume();
|
||||
if (match(TokenType::PrivateIdentifier)) {
|
||||
|
@ -2112,21 +2112,21 @@ NonnullRefPtr<Expression> Parser::parse_secondary_expression(NonnullRefPtr<Expre
|
|||
return create_ast_node<UpdateExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, UpdateOp::Decrement, move(lhs));
|
||||
case TokenType::DoubleAmpersand:
|
||||
consume();
|
||||
return create_ast_node<LogicalExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, LogicalOp::And, move(lhs), parse_expression(min_precedence, associativity));
|
||||
return create_ast_node<LogicalExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, LogicalOp::And, move(lhs), parse_expression(min_precedence, associativity, forbidden));
|
||||
case TokenType::DoubleAmpersandEquals:
|
||||
return parse_assignment_expression(AssignmentOp::AndAssignment, move(lhs), min_precedence, associativity);
|
||||
return parse_assignment_expression(AssignmentOp::AndAssignment, move(lhs), min_precedence, associativity, forbidden);
|
||||
case TokenType::DoublePipe:
|
||||
consume();
|
||||
return create_ast_node<LogicalExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, LogicalOp::Or, move(lhs), parse_expression(min_precedence, associativity));
|
||||
return create_ast_node<LogicalExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, LogicalOp::Or, move(lhs), parse_expression(min_precedence, associativity, forbidden));
|
||||
case TokenType::DoublePipeEquals:
|
||||
return parse_assignment_expression(AssignmentOp::OrAssignment, move(lhs), min_precedence, associativity);
|
||||
return parse_assignment_expression(AssignmentOp::OrAssignment, move(lhs), min_precedence, associativity, forbidden);
|
||||
case TokenType::DoubleQuestionMark:
|
||||
consume();
|
||||
return create_ast_node<LogicalExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, LogicalOp::NullishCoalescing, move(lhs), parse_expression(min_precedence, associativity));
|
||||
return create_ast_node<LogicalExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, LogicalOp::NullishCoalescing, move(lhs), parse_expression(min_precedence, associativity, forbidden));
|
||||
case TokenType::DoubleQuestionMarkEquals:
|
||||
return parse_assignment_expression(AssignmentOp::NullishAssignment, move(lhs), min_precedence, associativity);
|
||||
return parse_assignment_expression(AssignmentOp::NullishAssignment, move(lhs), min_precedence, associativity, forbidden);
|
||||
case TokenType::QuestionMark:
|
||||
return parse_conditional_expression(move(lhs));
|
||||
return parse_conditional_expression(move(lhs), forbidden);
|
||||
case TokenType::QuestionMarkPeriod:
|
||||
// FIXME: This should allow `(new Foo)?.bar', but as our parser strips parenthesis,
|
||||
// we can't really tell if `lhs' was parenthesized at this point.
|
||||
|
@ -2192,7 +2192,7 @@ RefPtr<BindingPattern> Parser::synthesize_binding_pattern(Expression const& expr
|
|||
return result;
|
||||
}
|
||||
|
||||
NonnullRefPtr<AssignmentExpression> Parser::parse_assignment_expression(AssignmentOp assignment_op, NonnullRefPtr<Expression> lhs, int min_precedence, Associativity associativity)
|
||||
NonnullRefPtr<AssignmentExpression> Parser::parse_assignment_expression(AssignmentOp assignment_op, NonnullRefPtr<Expression> lhs, int min_precedence, Associativity associativity, Vector<TokenType> const& forbidden)
|
||||
{
|
||||
auto rule_start = push_start();
|
||||
VERIFY(match(TokenType::Equals)
|
||||
|
@ -2234,7 +2234,7 @@ NonnullRefPtr<AssignmentExpression> Parser::parse_assignment_expression(Assignme
|
|||
} else if (m_state.strict_mode && is<CallExpression>(*lhs)) {
|
||||
syntax_error("Cannot assign to function call");
|
||||
}
|
||||
auto rhs = parse_expression(min_precedence, associativity);
|
||||
auto rhs = parse_expression(min_precedence, associativity, forbidden);
|
||||
return create_ast_node<AssignmentExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, assignment_op, move(lhs), move(rhs));
|
||||
}
|
||||
|
||||
|
@ -3026,13 +3026,13 @@ NonnullRefPtr<ContinueStatement> Parser::parse_continue_statement()
|
|||
return create_ast_node<ContinueStatement>({ m_state.current_token.filename(), rule_start.position(), position() }, target_label);
|
||||
}
|
||||
|
||||
NonnullRefPtr<ConditionalExpression> Parser::parse_conditional_expression(NonnullRefPtr<Expression> test)
|
||||
NonnullRefPtr<ConditionalExpression> Parser::parse_conditional_expression(NonnullRefPtr<Expression> test, Vector<TokenType> const& forbidden)
|
||||
{
|
||||
auto rule_start = push_start();
|
||||
consume(TokenType::QuestionMark);
|
||||
auto consequent = parse_expression(2);
|
||||
consume(TokenType::Colon);
|
||||
auto alternate = parse_expression(2);
|
||||
auto alternate = parse_expression(2, Associativity::Right, forbidden);
|
||||
return create_ast_node<ConditionalExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, move(test), move(consequent), move(alternate));
|
||||
}
|
||||
|
||||
|
|
|
@ -97,7 +97,7 @@ public:
|
|||
NonnullRefPtr<WhileStatement> parse_while_statement();
|
||||
NonnullRefPtr<WithStatement> parse_with_statement();
|
||||
NonnullRefPtr<DebuggerStatement> parse_debugger_statement();
|
||||
NonnullRefPtr<ConditionalExpression> parse_conditional_expression(NonnullRefPtr<Expression> test);
|
||||
NonnullRefPtr<ConditionalExpression> parse_conditional_expression(NonnullRefPtr<Expression> test, Vector<TokenType> const&);
|
||||
NonnullRefPtr<OptionalChain> parse_optional_chain(NonnullRefPtr<Expression> base);
|
||||
NonnullRefPtr<Expression> parse_expression(int min_precedence, Associativity associate = Associativity::Right, const Vector<TokenType>& forbidden = {});
|
||||
PrimaryExpressionParseResult parse_primary_expression();
|
||||
|
@ -107,7 +107,7 @@ public:
|
|||
NonnullRefPtr<ArrayExpression> parse_array_expression();
|
||||
NonnullRefPtr<StringLiteral> parse_string_literal(const Token& token, bool in_template_literal = false);
|
||||
NonnullRefPtr<TemplateLiteral> parse_template_literal(bool is_tagged);
|
||||
NonnullRefPtr<Expression> parse_secondary_expression(NonnullRefPtr<Expression>, int min_precedence, Associativity associate = Associativity::Right);
|
||||
NonnullRefPtr<Expression> parse_secondary_expression(NonnullRefPtr<Expression>, int min_precedence, Associativity associate = Associativity::Right, Vector<TokenType> const& forbidden = {});
|
||||
NonnullRefPtr<Expression> parse_call_expression(NonnullRefPtr<Expression>);
|
||||
NonnullRefPtr<NewExpression> parse_new_expression();
|
||||
NonnullRefPtr<ClassDeclaration> parse_class_declaration();
|
||||
|
@ -115,7 +115,7 @@ public:
|
|||
NonnullRefPtr<YieldExpression> parse_yield_expression();
|
||||
NonnullRefPtr<AwaitExpression> parse_await_expression();
|
||||
NonnullRefPtr<Expression> parse_property_key();
|
||||
NonnullRefPtr<AssignmentExpression> parse_assignment_expression(AssignmentOp, NonnullRefPtr<Expression> lhs, int min_precedence, Associativity);
|
||||
NonnullRefPtr<AssignmentExpression> parse_assignment_expression(AssignmentOp, NonnullRefPtr<Expression> lhs, int min_precedence, Associativity, Vector<TokenType> const& forbidden = {});
|
||||
NonnullRefPtr<Identifier> parse_identifier();
|
||||
NonnullRefPtr<ImportStatement> parse_import_statement(Program& program);
|
||||
NonnullRefPtr<ExportStatement> parse_export_statement(Program& program);
|
||||
|
|
19
Userland/Libraries/LibJS/Tests/syntax/for-loop-invalid-in.js
Normal file
19
Userland/Libraries/LibJS/Tests/syntax/for-loop-invalid-in.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
test("The use of the 'in' keyword is restricted in for loop headers", () => {
|
||||
expect("for (a ? a : a in a; false; ) ;").not.toEval();
|
||||
expect("for (a + a in b);").not.toEval();
|
||||
expect("for (a in a of a);").not.toEval();
|
||||
expect("for(a = a in a; false;);").not.toEval();
|
||||
expect("for(a += a in a; false;);").not.toEval();
|
||||
expect("for(a -= a in a; false;);").not.toEval();
|
||||
expect("for(a *= a in a; false;);").not.toEval();
|
||||
expect("for(a /= a in a; false;);").not.toEval();
|
||||
expect("for(a &= a in a; false;);").not.toEval();
|
||||
expect("for(a |= a in a; false;);").not.toEval();
|
||||
expect("for(a ^= a in a; false;);").not.toEval();
|
||||
expect("for(a ^^= a in a; false;);").not.toEval();
|
||||
expect("for(a == a in a; false;);").not.toEval();
|
||||
expect("for(a != a in a; false;);").not.toEval();
|
||||
expect("for(a === a in a; false;);").not.toEval();
|
||||
expect("for(a !== a in a; false;);").not.toEval();
|
||||
expect("for (a ?? b in c;;);").not.toEval();
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue