--- old/src/jdk/nashorn/internal/parser/Parser.java 2014-11-27 17:14:27.275205794 +0100 +++ new/src/jdk/nashorn/internal/parser/Parser.java 2014-11-27 17:14:27.147205797 +0100 @@ -559,7 +559,7 @@ // Set up new block. Captures first token. Block newBlock = newBlock(); try { - statement(); + statement(false, false, true); } finally { newBlock = restoreBlock(newBlock); } @@ -772,7 +772,7 @@ try { // Get the next element. - statement(true, allowPropertyFunction); + statement(true, allowPropertyFunction, false); allowPropertyFunction = false; // check for directive prologues @@ -862,13 +862,15 @@ * Parse any of the basic statement types. */ private void statement() { - statement(false, false); + statement(false, false, false); } /** * @param topLevel does this statement occur at the "top level" of a script or a function? + * @param allowPropertyFunction allow property "get" and "set" functions? + * @param singleStatement are we in a single statement context? */ - private void statement(final boolean topLevel, final boolean allowPropertyFunction) { + private void statement(final boolean topLevel, final boolean allowPropertyFunction, final boolean singleStatement) { if (type == FUNCTION) { // As per spec (ECMA section 12), function declarations as arbitrary statement // is not "portable". Implementation can issue a warning or disallow the same. @@ -932,6 +934,9 @@ break; default: if (useBlockScope() && (type == LET || type == CONST)) { + if (singleStatement) { + throw error(AbstractParser.message("expected.stmt", type.getName() + " declaration"), token); + } variableStatement(type, true); break; } @@ -1057,7 +1062,7 @@ next(); final List vars = new ArrayList<>(); - int varFlags = VarNode.IS_STATEMENT; + int varFlags = 0; if (varType == LET) { varFlags |= VarNode.IS_LET; } else if (varType == CONST) { @@ -1210,7 +1215,7 @@ Block outer = useBlockScope() ? newBlock() : null; // Create FOR node, capturing FOR token. - ForNode forNode = new ForNode(line, token, Token.descPosition(token), null, ForNode.IS_FOR); + ForNode forNode = new ForNode(line, token, Token.descPosition(token), null, 0); lc.push(forNode); try { @@ -1230,19 +1235,22 @@ switch (type) { case VAR: - // Var statements captured in for outer block. + // Var declaration captured in for outer block. vars = variableStatement(type, false); break; case SEMICOLON: break; default: if (useBlockScope() && (type == LET || type == CONST)) { - // LET/CONST captured in container block created above. + if (type == LET) { + forNode = forNode.setPerIterationScope(lc); + } + // LET/CONST declaration captured in container block created above. vars = variableStatement(type, false); break; } if (env._const_as_var && type == CONST) { - // Var statements captured in for outer block. + // Var declaration captured in for outer block. vars = variableStatement(TokenType.VAR, false); break; } @@ -1323,11 +1331,12 @@ appendStatement(forNode); } finally { lc.pop(forNode); - if (outer != null) { - outer.setFinish(forNode.getFinish()); - outer = restoreBlock(outer); - appendStatement(new BlockStatement(startLine, outer)); - } + } + + if (outer != null) { + outer.setFinish(forNode.getFinish()); + outer = restoreBlock(outer); + appendStatement(new BlockStatement(startLine, outer)); } } @@ -2699,11 +2708,7 @@ } if (isStatement) { - int varFlags = VarNode.IS_STATEMENT; - if (!topLevel && useBlockScope()) { - // mark ES6 block functions as lexically scoped - varFlags |= VarNode.IS_LET; - } + final int varFlags = (topLevel || !useBlockScope()) ? 0 : VarNode.IS_LET; final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, functionNode, varFlags); if (topLevel) { functionDeclarations.add(varNode);