Cleanup in the parser

- Move break/continue check from ValidationEnvironment to the Parser
- Remove some differences between BUILD / Skylark parsing mode
- Fix location off-by-one error in the break/continue tokens
- Remove duplicated error message ('for loops are not allowed on top-level')

--
MOS_MIGRATED_REVID=137259929
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Parser.java b/src/main/java/com/google/devtools/build/lib/syntax/Parser.java
index 4101062..8b28b3e 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/Parser.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/Parser.java
@@ -135,6 +135,7 @@
 
   private Token token; // current lookahead token
   private Token pushedToken = null; // used to implement LL(2)
+  private int loopCount; // break/continue keywords can be used only inside a loop
 
   private static final boolean DEBUGGING = false;
 
@@ -1171,8 +1172,7 @@
     int start = token.left;
     if (token.kind == TokenKind.RETURN) {
       return parseReturnStatement();
-    } else if ((parsingMode == SKYLARK)
-        && (token.kind == TokenKind.BREAK || token.kind == TokenKind.CONTINUE)) {
+    } else if (token.kind == TokenKind.BREAK || token.kind == TokenKind.CONTINUE) {
       return parseFlowStatement(token.kind);
     }
     Expression expression = parseExpression();
@@ -1232,9 +1232,14 @@
     expect(TokenKind.IN);
     Expression collection = parseExpression();
     expect(TokenKind.COLON);
-    List<Statement> block = parseSuite();
-    Statement stmt = new ForStatement(loopVar, collection, block);
-    list.add(setLocation(stmt, start, token.right));
+    enterLoop();
+    try {
+      List<Statement> block = parseSuite();
+      Statement stmt = new ForStatement(loopVar, collection, block);
+      list.add(setLocation(stmt, start, token.right));
+    } finally {
+      exitLoop();
+    }
   }
 
   // def foo(bar1, bar2):
@@ -1401,10 +1406,16 @@
   // flow_stmt ::= break_stmt | continue_stmt
   private FlowStatement parseFlowStatement(TokenKind kind) {
     int start = token.left;
+    int end = token.right;
     expect(kind);
+    if (loopCount == 0) {
+      reportError(
+          lexer.createLocation(start, end),
+          kind.getPrettyName() + " statement must be inside a for loop");
+    }
     FlowStatement.Kind flowKind =
         kind == TokenKind.BREAK ? FlowStatement.Kind.BREAK : FlowStatement.Kind.CONTINUE;
-    return setLocation(new FlowStatement(flowKind), start, token.right);
+    return setLocation(new FlowStatement(flowKind), start, end);
   }
 
   // return_stmt ::= RETURN [expr]
@@ -1429,7 +1440,7 @@
     int start = token.left;
     Token blockToken = token;
     syncTo(EnumSet.of(TokenKind.COLON, TokenKind.EOF)); // skip over expression or name
-    if (blockToken.kind == TokenKind.ELSE && parsingMode == SKYLARK) {
+    if (blockToken.kind == TokenKind.ELSE) {
       reportError(
           lexer.createLocation(blockToken.left, blockToken.right),
           "syntax error at 'else': not allowed here.");
@@ -1450,4 +1461,13 @@
   private void makeComment(Token token) {
     comments.add(setLocation(new Comment((String) token.value), token.left, token.right));
   }
+
+  private void enterLoop() {
+    loopCount++;
+  }
+
+  private void exitLoop() {
+    Preconditions.checkState(loopCount > 0);
+    loopCount--;
+  }
 }