diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp index 0a758197c0..c9538e61dd 100644 --- a/Libraries/LibJS/AST.cpp +++ b/Libraries/LibJS/AST.cpp @@ -251,6 +251,9 @@ Value ForStatement::execute(Interpreter& interpreter) const if (m_init && m_init->is_variable_declaration() && static_cast(m_init.ptr())->declaration_kind() != DeclarationKind::Var) { wrapper = create_ast_node(); + NonnullRefPtrVector decls; + decls.append(*static_cast(m_init.ptr())); + wrapper->add_variables(decls); interpreter.enter_scope(*wrapper, {}, ScopeType::Block); } diff --git a/Libraries/LibJS/Parser.cpp b/Libraries/LibJS/Parser.cpp index 9ca17144a5..454c94922a 100644 --- a/Libraries/LibJS/Parser.cpp +++ b/Libraries/LibJS/Parser.cpp @@ -1133,6 +1133,7 @@ NonnullRefPtr Parser::parse_for_statement() consume(TokenType::ParenOpen); bool first_semicolon_consumed = false; + bool in_scope = false; RefPtr init; switch (m_parser_state.m_current_token.type()) { case TokenType::Semicolon: @@ -1141,6 +1142,11 @@ NonnullRefPtr Parser::parse_for_statement() if (match_expression()) { init = parse_expression(0); } else if (match_variable_declaration()) { + if (m_parser_state.m_current_token.type() != TokenType::Var) { + m_parser_state.m_let_scopes.append(NonnullRefPtrVector()); + in_scope = true; + } + init = parse_variable_declaration(); first_semicolon_consumed = true; } else { @@ -1176,6 +1182,10 @@ NonnullRefPtr Parser::parse_for_statement() auto body = parse_statement(); + if (in_scope) { + m_parser_state.m_let_scopes.take_last(); + } + return create_ast_node(move(init), move(test), move(update), move(body)); } diff --git a/Libraries/LibJS/Tests/for-scopes.js b/Libraries/LibJS/Tests/for-scopes.js new file mode 100644 index 0000000000..00c6a96c88 --- /dev/null +++ b/Libraries/LibJS/Tests/for-scopes.js @@ -0,0 +1,22 @@ +load("test-common.js"); + +try { + for (var v = 5; false; ); + assert(v == 5); + + const options = {error: ReferenceError}; + + assertThrowsError(() => { + for (let l = 5; false; ); + l; + }, options); + + assertThrowsError(() => { + for (const c = 5; false; ); + c; + }, options) + + console.log("PASS"); +} catch (e) { + console.log("FAIL: " + e); +}