From 2a61b90fefe2064ada003d284fc37537f9efa5c8 Mon Sep 17 00:00:00 2001 From: davidot Date: Mon, 12 Jul 2021 01:25:32 +0200 Subject: [PATCH] LibJS: Be less strict about 'use strict' It is allowed to have (bogus) directives e.g. 'does nothing'; 'same'; 'use strict'; Should still trigger strict mode. --- Userland/Libraries/LibJS/Parser.cpp | 41 +++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/Userland/Libraries/LibJS/Parser.cpp b/Userland/Libraries/LibJS/Parser.cpp index da6ab77466c..9a1349affc8 100644 --- a/Userland/Libraries/LibJS/Parser.cpp +++ b/Userland/Libraries/LibJS/Parser.cpp @@ -286,26 +286,36 @@ NonnullRefPtr Parser::parse_program(bool starts_in_strict_mode) m_state.strict_mode = true; } - bool first = true; + bool parsing_directives = true; while (!done()) { if (match_declaration()) { program->append(parse_declaration()); + parsing_directives = false; } else if (match_statement()) { auto statement = parse_statement(); program->append(statement); if (statement_is_use_strict_directive(statement)) { - if (first) { + if (parsing_directives) { program->set_strict_mode(); m_state.strict_mode = true; } if (m_state.string_legacy_octal_escape_sequence_in_scope) syntax_error("Octal escape sequence in string literal not allowed in strict mode"); } + + if (parsing_directives && is(*statement)) { + auto& expression_statement = static_cast(*statement); + auto& expression = expression_statement.expression(); + parsing_directives = is(expression); + } else { + parsing_directives = false; + } + } else { expected("statement or declaration"); consume(); + parsing_directives = false; } - first = false; } if (m_state.var_scopes.size() == 1) { scope.add_to_scope_node(program); @@ -1511,30 +1521,45 @@ NonnullRefPtr Parser::parse_block_statement(bool& is_strict) auto block = create_ast_node({ m_state.current_token.filename(), rule_start.position(), position() }); consume(TokenType::CurlyOpen); - bool first = true; bool initial_strict_mode_state = m_state.strict_mode; if (initial_strict_mode_state) is_strict = true; + bool parsing_directives = true; while (!done() && !match(TokenType::CurlyClose)) { if (match_declaration()) { block->append(parse_declaration()); + parsing_directives = false; } else if (match_statement()) { auto statement = parse_statement(); block->append(statement); if (statement_is_use_strict_directive(statement)) { - if (first && !initial_strict_mode_state) { - is_strict = true; - m_state.strict_mode = true; + if (parsing_directives) { + if (!initial_strict_mode_state) { + is_strict = true; + m_state.strict_mode = true; + } } if (m_state.string_legacy_octal_escape_sequence_in_scope) syntax_error("Octal escape sequence in string literal not allowed in strict mode"); + + if (has_binding) { + syntax_error("Illegal 'use strict' directive in function with non-simple parameter list"); + } + } + + if (parsing_directives && is(*statement)) { + auto& expression_statement = static_cast(*statement); + auto& expression = expression_statement.expression(); + parsing_directives = is(expression); + } else { + parsing_directives = false; } } else { expected("statement or declaration"); consume(); + parsing_directives = false; } - first = false; } m_state.strict_mode = initial_strict_mode_state; m_state.string_legacy_octal_escape_sequence_in_scope = false;