src/jdk/nashorn/internal/parser/Parser.java

Print this page

        

@@ -557,11 +557,11 @@
             return getBlock(true);
         }
         // Set up new block. Captures first token.
         Block newBlock = newBlock();
         try {
-            statement();
+            statement(false, false, true);
         } finally {
             newBlock = restoreBlock(newBlock);
         }
         return newBlock;
     }

@@ -770,11 +770,11 @@
                     break;
                 }
 
                 try {
                     // Get the next element.
-                    statement(true, allowPropertyFunction);
+                    statement(true, allowPropertyFunction, false);
                     allowPropertyFunction = false;
 
                     // check for directive prologues
                     if (checkDirective) {
                         // skip any debug statement like line number to get actual first line

@@ -860,17 +860,19 @@
      * see 12
      *
      * 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.
             functionExpression(true, topLevel);
             return;

@@ -930,10 +932,13 @@
         case EOF:
             expect(SEMICOLON);
             break;
         default:
             if (useBlockScope() && (type == LET || type == CONST)) {
+                if (singleStatement) {
+                    throw error(AbstractParser.message("expected.stmt", type.getName() + " declaration"), token);
+                }
                 variableStatement(type, true);
                 break;
             }
             if (env._const_as_var && type == CONST) {
                 variableStatement(TokenType.VAR, true);

@@ -1055,11 +1060,11 @@
     private List<VarNode> variableStatement(final TokenType varType, final boolean isStatement) {
         // VAR tested in caller.
         next();
 
         final List<VarNode> vars = new ArrayList<>();
-        int varFlags = VarNode.IS_STATEMENT;
+        int varFlags = 0;
         if (varType == LET) {
             varFlags |= VarNode.IS_LET;
         } else if (varType == CONST) {
             varFlags |= VarNode.IS_CONST;
         }

@@ -1208,11 +1213,11 @@
         // When ES6 for-let is enabled we create a container block to capture the LET.
         final int startLine = start;
         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 {
             // FOR tested in caller.
             next();

@@ -1228,23 +1233,26 @@
 
             List<VarNode> vars = null;
 
             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;
                 }
 
                 final Expression expression = expression(unaryExpression(), COMMARIGHT.getPrecedence(), true);

@@ -1321,17 +1329,18 @@
             forNode.setFinish(body.getFinish());
 
             appendStatement(forNode);
         } finally {
             lc.pop(forNode);
+        }
+
             if (outer != null) {
                 outer.setFinish(forNode.getFinish());
                 outer = restoreBlock(outer);
                 appendStatement(new BlockStatement(startLine, outer));
             }
         }
-    }
 
     /**
      * ... IterationStatement :
      *           ...
      *           Expression[NoIn]?; Expression? ; Expression?

@@ -2697,15 +2706,11 @@
                 functionNode = functionNode.setFlag(lc, FunctionNode.DEFINES_ARGUMENTS);
             }
         }
 
         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);
             } else if (useBlockScope()) {
                 prependStatement(varNode); // Hoist to beginning of current block