1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 11:08:11 +00:00

LibJS: Disallow 'continue' & 'break' outside of their respective scopes

'continue' is no longer allowed outside of a loop, and an unlabeled
'break' is not longer allowed outside of a loop or switch statement.
Labeled 'break' statements are still allowed everywhere, even if the
label does not exist.
This commit is contained in:
Matthew Olsson 2020-10-07 12:21:15 -07:00 committed by Andreas Kling
parent b85af075b7
commit e49ea1b520
3 changed files with 44 additions and 5 deletions

View file

@ -1394,16 +1394,23 @@ NonnullRefPtr<BreakStatement> Parser::parse_break_statement()
FlyString target_label;
if (match(TokenType::Semicolon)) {
consume();
return create_ast_node<BreakStatement>(target_label);
} else {
if (match(TokenType::Identifier) && !m_parser_state.m_current_token.trivia().contains('\n'))
target_label = consume().value();
consume_or_insert_semicolon();
}
if (match(TokenType::Identifier) && !m_parser_state.m_current_token.trivia().contains('\n'))
target_label = consume().value();
consume_or_insert_semicolon();
if (target_label.is_null() && !m_parser_state.m_in_break_context)
syntax_error("Unlabeled 'break' not allowed outside of a loop or switch statement");
return create_ast_node<BreakStatement>(target_label);
}
NonnullRefPtr<ContinueStatement> Parser::parse_continue_statement()
{
if (!m_parser_state.m_in_continue_context)
syntax_error("'continue' not allow outside of a loop");
consume(TokenType::Continue);
FlyString target_label;
if (match(TokenType::Semicolon)) {
@ -1448,7 +1455,11 @@ NonnullRefPtr<DoWhileStatement> Parser::parse_do_while_statement()
{
consume(TokenType::Do);
auto body = parse_statement();
auto body = [&]() -> NonnullRefPtr<Statement> {
TemporaryChange break_change(m_parser_state.m_in_break_context, true);
TemporaryChange continue_change(m_parser_state.m_in_continue_context, true);
return parse_statement();
}();
consume(TokenType::While);
consume(TokenType::ParenOpen);
@ -1470,6 +1481,8 @@ NonnullRefPtr<WhileStatement> Parser::parse_while_statement()
consume(TokenType::ParenClose);
TemporaryChange break_change(m_parser_state.m_in_break_context, true);
TemporaryChange continue_change(m_parser_state.m_in_continue_context, true);
auto body = parse_statement();
return create_ast_node<WhileStatement>(move(test), move(body));
@ -1506,6 +1519,7 @@ NonnullRefPtr<SwitchCase> Parser::parse_switch_case()
consume(TokenType::Colon);
NonnullRefPtrVector<Statement> consequent;
TemporaryChange break_change(m_parser_state.m_in_break_context, true);
while (match_statement())
consequent.append(parse_statement());
@ -1585,6 +1599,8 @@ NonnullRefPtr<Statement> Parser::parse_for_statement()
consume(TokenType::ParenClose);
TemporaryChange break_change(m_parser_state.m_in_break_context, true);
TemporaryChange continue_change(m_parser_state.m_in_continue_context, true);
auto body = parse_statement();
if (in_scope) {
@ -1610,6 +1626,9 @@ NonnullRefPtr<Statement> Parser::parse_for_in_of_statement(NonnullRefPtr<ASTNode
auto in_or_of = consume();
auto rhs = parse_expression(0);
consume(TokenType::ParenClose);
TemporaryChange break_change(m_parser_state.m_in_break_context, true);
TemporaryChange continue_change(m_parser_state.m_in_continue_context, true);
auto body = parse_statement();
if (in_or_of.type() == TokenType::In)
return create_ast_node<ForInStatement>(move(lhs), move(rhs), move(body));