Add Forest support for for statements

Change-Id: Ic65a09c01012e8a5d0ab2a4f755950c18b00fa9f
Reviewed-on: https://dart-review.googlesource.com/56000
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Dan Rubel <danrubel@google.com>
diff --git a/pkg/analyzer/lib/src/fasta/ast_building_factory.dart b/pkg/analyzer/lib/src/fasta/ast_building_factory.dart
index 8c06134..28b8ae0 100644
--- a/pkg/analyzer/lib/src/fasta/ast_building_factory.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_building_factory.dart
@@ -141,6 +141,45 @@
       astFactory.expressionStatement(expression, semicolon);
 
   @override
+  Statement forStatement(
+          Token forKeyword,
+          Token leftParenthesis,
+          covariant variableList,
+          covariant initialization,
+          Token leftSeparator,
+          Expression condition,
+          Token rightSeparator,
+          List<Expression> updaters,
+          Token rightParenthesis,
+          Statement body) =>
+      astFactory.forStatement(
+          forKeyword,
+          leftParenthesis,
+          variableList,
+          initialization,
+          leftSeparator,
+          condition,
+          rightSeparator,
+          updaters,
+          rightParenthesis,
+          body);
+
+  @override
+  Expression getExpressionFromExpressionStatement(Statement statement) =>
+      (statement as ExpressionStatement).expression;
+
+  @override
+  Token getSemicolon(Statement statement) {
+    if (statement is ExpressionStatement) {
+      return statement.semicolon;
+    }
+    if (statement is EmptyStatement) {
+      return statement.semicolon;
+    }
+    return null;
+  }
+
+  @override
   kernel.DartType getTypeAt(TypeArgumentList typeArguments, int index) {
     return null; // typeArguments.arguments[index].type.kernelType;
   }
@@ -166,9 +205,24 @@
           elseStatement);
 
   @override
+  Generator<Expression, Statement, _Arguments> indexedAccessGenerator(
+      ExpressionGeneratorHelper<Expression, Statement, _Arguments> helper,
+      Token token,
+      Expression receiver,
+      Expression index,
+      kernel.Procedure getter,
+      kernel.Procedure setter) {
+    // TODO(brianwilkerson): Implement this.
+    throw new UnimplementedError();
+  }
+
+  @override
   bool isBlock(Object node) => node is Block;
 
   @override
+  bool isEmptyStatement(Statement statement) => statement is EmptyStatement;
+
+  @override
   bool isErroneousNode(Object node) => false /* ??? */;
 
   @override
@@ -177,6 +231,10 @@
       astFactory.isExpression(expression, isOperator, notOperator, type);
 
   @override
+  bool isExpressionStatement(Statement statement) =>
+      statement is ExpressionStatement;
+
+  @override
   bool isThisExpression(Object node) => node is ThisExpression;
 
   @override
@@ -280,12 +338,37 @@
         ..staticType = _typeProvider?.boolType;
 
   @override
+  Generator<Expression, Statement, _Arguments> nullAwarePropertyAccessGenerator(
+      ExpressionGeneratorHelper<Expression, Statement, _Arguments> helper,
+      Token token,
+      Expression receiverExpression,
+      kernel.Name name,
+      kernel.Member getter,
+      kernel.Member setter,
+      kernel.DartType type) {
+    // TODO(brianwilkerson): Implement this.
+    throw new UnimplementedError();
+  }
+
+  @override
   Object parenthesizedCondition(Token leftParenthesis, Expression expression,
           Token rightParenthesis) =>
       astFactory.parenthesizedExpression(
           leftParenthesis, expression, rightParenthesis);
 
   @override
+  Generator<Expression, Statement, _Arguments> propertyAccessGenerator(
+      ExpressionGeneratorHelper<Expression, Statement, _Arguments> helper,
+      Token token,
+      Expression receiver,
+      kernel.Name name,
+      kernel.Member getter,
+      kernel.Member setter) {
+    // TODO(brianwilkerson): Implement this.
+    throw new UnimplementedError();
+  }
+
+  @override
   int readOffset(AstNode node) => node.offset;
 
   @override
@@ -319,6 +402,17 @@
       astFactory.adjacentStrings(strings.cast<StringLiteral>());
 
   @override
+  Generator<Expression, Statement, _Arguments> superPropertyAccessGenerator(
+      ExpressionGeneratorHelper<Expression, Statement, _Arguments> helper,
+      Token token,
+      kernel.Name name,
+      kernel.Member getter,
+      kernel.Member setter) {
+    // TODO(brianwilkerson): Implement this.
+    throw new UnimplementedError();
+  }
+
+  @override
   Statement syntheticLabeledStatement(Statement statement) => statement;
 
   @override
@@ -326,6 +420,28 @@
       astFactory.thisExpression(thisKeyword);
 
   @override
+  Generator<Expression, Statement, _Arguments> thisIndexedAccessGenerator(
+      ExpressionGeneratorHelper<Expression, Statement, _Arguments> helper,
+      Token token,
+      Expression index,
+      kernel.Procedure getter,
+      kernel.Procedure setter) {
+    // TODO(brianwilkerson): Implement this.
+    throw new UnimplementedError();
+  }
+
+  @override
+  Generator<Expression, Statement, _Arguments> thisPropertyAccessGenerator(
+      ExpressionGeneratorHelper<Expression, Statement, _Arguments> helper,
+      Token location,
+      kernel.Name name,
+      kernel.Member getter,
+      kernel.Member setter) {
+    // TODO(brianwilkerson): Implement this.
+    throw new UnimplementedError();
+  }
+
+  @override
   Expression throwExpression(Token throwKeyword, Expression expression) =>
       astFactory.throwExpression(throwKeyword, expression);
 
@@ -352,6 +468,15 @@
       variablesDeclaration.variables.variables;
 
   @override
+  Generator<Expression, Statement, _Arguments> variableUseGenerator(
+      ExpressionGeneratorHelper<Expression, Statement, _Arguments> helper,
+      Token token,
+      VariableDeclarationStatement variable,
+      kernel.DartType promotedType) {
+    // TODO(brianwilkerson) Implement this.
+    throw new UnimplementedError();
+  }
+
   Statement whileStatement(Token whileKeyword,
           ParenthesizedExpression condition, Statement body) =>
       astFactory.whileStatement(whileKeyword, condition.leftParenthesis,
@@ -364,86 +489,6 @@
   Statement yieldStatement(Token yieldKeyword, Token star,
           Expression expression, Token semicolon) =>
       astFactory.yieldStatement(yieldKeyword, star, expression, semicolon);
-
-  @override
-  Generator<Expression, Statement, _Arguments> variableUseGenerator(
-      ExpressionGeneratorHelper<Expression, Statement, _Arguments> helper,
-      Token token,
-      VariableDeclarationStatement variable,
-      kernel.DartType promotedType) {
-    // TODO(brianwilkerson) Implement this.
-    throw new UnimplementedError();
-  }
-
-  @override
-  Generator<Expression, Statement, _Arguments> propertyAccessGenerator(
-      ExpressionGeneratorHelper<Expression, Statement, _Arguments> helper,
-      Token token,
-      Expression receiver,
-      kernel.Name name,
-      kernel.Member getter,
-      kernel.Member setter) {
-    // TODO(brianwilkerson) Implement this.
-    throw new UnimplementedError();
-  }
-
-  @override
-  Generator<Expression, Statement, _Arguments> thisPropertyAccessGenerator(
-      ExpressionGeneratorHelper<Expression, Statement, _Arguments> helper,
-      Token location,
-      kernel.Name name,
-      kernel.Member getter,
-      kernel.Member setter) {
-    // TODO(brianwilkerson) Implement this.
-    throw new UnimplementedError();
-  }
-
-  @override
-  Generator<Expression, Statement, _Arguments> nullAwarePropertyAccessGenerator(
-      ExpressionGeneratorHelper<Expression, Statement, _Arguments> helper,
-      Token token,
-      Expression receiverExpression,
-      kernel.Name name,
-      kernel.Member getter,
-      kernel.Member setter,
-      kernel.DartType type) {
-    // TODO(brianwilkerson) Implement this.
-    throw new UnimplementedError();
-  }
-
-  @override
-  Generator<Expression, Statement, _Arguments> superPropertyAccessGenerator(
-      ExpressionGeneratorHelper<Expression, Statement, _Arguments> helper,
-      Token token,
-      kernel.Name name,
-      kernel.Member getter,
-      kernel.Member setter) {
-    // TODO(brianwilkerson): Implement this.
-    throw new UnimplementedError();
-  }
-
-  @override
-  Generator<Expression, Statement, _Arguments> indexedAccessGenerator(
-      ExpressionGeneratorHelper<Expression, Statement, _Arguments> helper,
-      Token token,
-      Expression receiver,
-      Expression index,
-      kernel.Procedure getter,
-      kernel.Procedure setter) {
-    // TODO(brianwilkerson): Implement this.
-    throw new UnimplementedError();
-  }
-
-  @override
-  Generator<Expression, Statement, _Arguments> thisIndexedAccessGenerator(
-      ExpressionGeneratorHelper<Expression, Statement, _Arguments> helper,
-      Token token,
-      Expression index,
-      kernel.Procedure getter,
-      kernel.Procedure setter) {
-    // TODO(brianwilkerson): Implement this.
-    throw new UnimplementedError();
-  }
 }
 
 /// A data holder used to conform to the [Forest] API.
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index 7cb74e5..2fc31e8 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -1839,14 +1839,6 @@
     Statement body = popStatement();
     List<Expression> updates = popListForEffect(updateExpressionCount);
     Statement conditionStatement = popStatement();
-    kernel.Statement kernelConditionStatement =
-        toKernelStatement(conditionStatement);
-    Expression condition = null;
-    if (kernelConditionStatement is ExpressionStatement) {
-      condition = toExpression(kernelConditionStatement.expression);
-    } else {
-      assert(kernelConditionStatement is EmptyStatement);
-    }
     dynamic variableOrExpression = pop();
     List<VariableDeclaration> variables =
         buildVariableDeclarations(variableOrExpression);
@@ -1857,22 +1849,36 @@
     exitLocalScope();
     JumpTarget continueTarget = exitContinueTarget();
     JumpTarget breakTarget = exitBreakTarget();
-    kernel.Statement kernelBody = toKernelStatement(body);
     if (continueTarget.hasUsers) {
-      kernelBody = new ShadowLabeledStatement(kernelBody);
-      continueTarget.resolveContinues(forest, kernelBody);
+      body = forest.syntheticLabeledStatement(body);
+      continueTarget.resolveContinues(forest, body);
     }
-    kernel.Statement result = new ShadowForStatement(
+    Expression condition;
+    Token rightSeparator;
+    if (forest.isExpressionStatement(conditionStatement)) {
+      condition =
+          forest.getExpressionFromExpressionStatement(conditionStatement);
+      rightSeparator = forest.getSemicolon(conditionStatement);
+    } else {
+      assert(forest.isEmptyStatement(conditionStatement));
+      rightSeparator = forest.getSemicolon(conditionStatement);
+    }
+    Statement result = forest.forStatement(
+        forKeyword,
+        leftParen,
         variables,
-        toKernelExpression(condition),
-        toKernelExpressionList(updates),
-        kernelBody)
-      ..fileOffset = forKeyword.charOffset;
+        variables,
+        leftSeparator,
+        condition,
+        rightSeparator,
+        updates,
+        leftParen.endGroup,
+        body);
     if (breakTarget.hasUsers) {
-      result = new ShadowLabeledStatement(result);
+      result = forest.syntheticLabeledStatement(result);
       breakTarget.resolveBreaks(forest, result);
     }
-    exitLoopOrSwitch(toStatement(result));
+    exitLoopOrSwitch(result);
   }
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/kernel/fangorn.dart b/pkg/front_end/lib/src/fasta/kernel/fangorn.dart
index f4de49e..1490aff 100644
--- a/pkg/front_end/lib/src/fasta/kernel/fangorn.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/fangorn.dart
@@ -65,6 +65,7 @@
         ShadowDoStatement,
         ShadowDoubleLiteral,
         ShadowExpressionStatement,
+        ShadowForStatement,
         ShadowIfStatement,
         ShadowIntLiteral,
         ShadowIsExpression,
@@ -351,6 +352,22 @@
   }
 
   @override
+  Statement forStatement(
+      Token forKeyword,
+      Token leftParenthesis,
+      List<VariableDeclaration> variableList,
+      covariant initialization,
+      Token leftSeparator,
+      Expression condition,
+      Token rightSeparator,
+      List<Expression> updaters,
+      Token rightParenthesis,
+      Statement body) {
+    return new ShadowForStatement(variableList, condition, updaters, body)
+      ..fileOffset = forKeyword.charOffset;
+  }
+
+  @override
   Statement ifStatement(Token ifKeyword, Expression condition,
       Statement thenStatement, Token elseKeyword, Statement elseStatement) {
     return new ShadowIfStatement(condition, thenStatement, elseStatement)
@@ -467,9 +484,20 @@
   }
 
   @override
+  Expression getExpressionFromExpressionStatement(Statement statement) {
+    return (statement as ExpressionStatement).expression;
+  }
+
+  @override
+  Token getSemicolon(Statement statement) => null;
+
+  @override
   bool isBlock(Object node) => node is Block;
 
   @override
+  bool isEmptyStatement(Statement statement) => statement is EmptyStatement;
+
+  @override
   bool isErroneousNode(Object node) {
     if (node is ExpressionStatement) {
       ExpressionStatement statement = node;
@@ -491,6 +519,10 @@
   }
 
   @override
+  bool isExpressionStatement(Statement statement) =>
+      statement is ExpressionStatement;
+
+  @override
   bool isThisExpression(Object node) => node is ThisExpression;
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/kernel/forest.dart b/pkg/front_end/lib/src/fasta/kernel/forest.dart
index 50f9c48..2589526 100644
--- a/pkg/front_end/lib/src/fasta/kernel/forest.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/forest.dart
@@ -201,6 +201,19 @@
   /// [semicolon].
   Statement emptyStatement(Location semicolon);
 
+  /// Return a representation of a for statement.
+  Statement forStatement(
+      Location forKeyword,
+      Location leftParenthesis,
+      covariant variableList,
+      covariant initialization,
+      Location leftSeparator,
+      Expression condition,
+      Location rightSeparator,
+      List<Expression> updaters,
+      Location rightParenthesis,
+      Statement body);
+
   /// Return a representation of an `if` statement.
   Statement ifStatement(Location ifKeyword, covariant Expression condition,
       Statement thenStatement, Location elseKeyword, Statement elseStatement);
@@ -270,10 +283,25 @@
   Statement yieldStatement(Location yieldKeyword, Location star,
       Expression expression, Location semicolon);
 
+  /// Return the expression from the given expression [statement].
+  Expression getExpressionFromExpressionStatement(Statement statement);
+
+  /// Return the semicolon at the end of the given [statement], or `null` if the
+  /// statement is not terminated by a semicolon.
+  Location getSemicolon(Statement statement);
+
   bool isBlock(Object node);
 
+  /// Return `true` if the given [statement] is the representation of an empty
+  /// statement.
+  bool isEmptyStatement(Statement statement);
+
   bool isErroneousNode(Object node);
 
+  /// Return `true` if the given [statement] is the representation of an
+  /// expression statement.
+  bool isExpressionStatement(Statement statement);
+
   bool isThisExpression(Object node);
 
   bool isVariablesDeclaration(Object node);
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_ast_api.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_ast_api.dart
index 6817deb..33906b3 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_ast_api.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_ast_api.dart
@@ -76,7 +76,6 @@
         ShadowFactoryConstructorInvocation,
         ShadowFieldInitializer,
         ShadowForInStatement,
-        ShadowForStatement,
         ShadowFunctionDeclaration,
         ShadowFunctionExpression,
         ShadowIfNullExpression,