Add Forest support for while statements
Change-Id: Iffec7799642a44fc6ab2b5f8b7493135d2d05ac5
Reviewed-on: https://dart-review.googlesource.com/55906
Reviewed-by: Dan Rubel <danrubel@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@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 5980a25..ae79499 100644
--- a/pkg/analyzer/lib/src/fasta/ast_building_factory.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_building_factory.dart
@@ -239,6 +239,21 @@
int readOffset(AstNode node) => node.offset;
@override
+ void resolveBreak(Statement target, BreakStatement user) {
+ user.target = target;
+ }
+
+ @override
+ void resolveContinue(Statement target, ContinueStatement user) {
+ user.target = target;
+ }
+
+ @override
+ void resolveContinueInSwitch(SwitchStatement target, ContinueStatement user) {
+ user.target = target;
+ }
+
+ @override
Statement rethrowStatement(Token rethrowKeyword, Token semicolon) =>
astFactory.expressionStatement(
astFactory.rethrowExpression(rethrowKeyword), semicolon);
@@ -249,6 +264,9 @@
astFactory.adjacentStrings(strings.cast<StringLiteral>());
@override
+ Statement syntheticLabeledStatement(Statement statement) => statement;
+
+ @override
Expression thisExpression(Token thisKeyword) =>
astFactory.thisExpression(thisKeyword);
@@ -280,6 +298,12 @@
}
@override
+ Statement whileStatement(Token whileKeyword,
+ ParenthesizedExpression condition, Statement body) =>
+ astFactory.whileStatement(whileKeyword, condition.leftParenthesis,
+ condition.expression, condition.rightParenthesis, body);
+
+ @override
Statement wrapVariables(Statement statement) => statement;
@override
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 2ca4888..64a8c0a 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -12,6 +12,8 @@
import '../fasta_codes.dart' show LocatedMessage, Message, noLength, Template;
+import 'forest.dart' show Forest;
+
import '../messages.dart' as messages show getLocationFromUri;
import '../modifier.dart' show Modifier, constMask, covariantMask, finalMask;
@@ -408,7 +410,8 @@
@override
JumpTarget createJumpTarget(JumpTargetKind kind, int charOffset) {
- return new JumpTarget(kind, functionNestingLevel, member, charOffset);
+ return new JumpTarget<Statement>(
+ kind, functionNestingLevel, member, charOffset);
}
@override
@@ -1810,7 +1813,7 @@
}
}
- void exitLoopOrSwitch(kernel.Statement statement) {
+ void exitLoopOrSwitch(Statement statement) {
if (compileTimeErrorInLoopOrSwitch != null) {
push(compileTimeErrorInLoopOrSwitch);
compileTimeErrorInLoopOrSwitch = null;
@@ -1876,7 +1879,7 @@
kernel.Statement kernelBody = toKernelStatement(body);
if (continueTarget.hasUsers) {
kernelBody = new ShadowLabeledStatement(kernelBody);
- continueTarget.resolveContinues(kernelBody);
+ continueTarget.resolveContinues(forest, kernelBody);
}
kernel.Statement result = new ShadowForStatement(
variables,
@@ -1886,9 +1889,9 @@
..fileOffset = forKeyword.charOffset;
if (breakTarget.hasUsers) {
result = new ShadowLabeledStatement(result);
- breakTarget.resolveBreaks(result);
+ breakTarget.resolveBreaks(forest, result);
}
- exitLoopOrSwitch(result);
+ exitLoopOrSwitch(toStatement(result));
}
@override
@@ -3152,16 +3155,16 @@
kernel.Statement kernelBody = toKernelStatement(body);
if (continueTarget.hasUsers) {
kernelBody = new ShadowLabeledStatement(kernelBody);
- continueTarget.resolveContinues(kernelBody);
+ continueTarget.resolveContinues(forest, kernelBody);
}
kernel.Statement result =
new ShadowDoStatement(kernelBody, toKernelExpression(condition))
..fileOffset = doKeyword.charOffset;
if (breakTarget.hasUsers) {
result = new ShadowLabeledStatement(result);
- breakTarget.resolveBreaks(result);
+ breakTarget.resolveBreaks(forest, result);
}
- exitLoopOrSwitch(result);
+ exitLoopOrSwitch(toStatement(result));
}
@override
@@ -3190,7 +3193,7 @@
kernel.Statement kernelBody = toKernelStatement(body);
if (continueTarget.hasUsers) {
kernelBody = new ShadowLabeledStatement(kernelBody);
- continueTarget.resolveContinues(kernelBody);
+ continueTarget.resolveContinues(forest, kernelBody);
}
VariableDeclaration variable;
bool declaresVariable = false;
@@ -3243,9 +3246,9 @@
..bodyOffset = kernelBody.fileOffset;
if (breakTarget.hasUsers) {
result = new ShadowLabeledStatement(result);
- breakTarget.resolveBreaks(result);
+ breakTarget.resolveBreaks(forest, result);
}
- exitLoopOrSwitch(result);
+ exitLoopOrSwitch(toStatement(result));
}
@override
@@ -3260,8 +3263,8 @@
debugEvent("beginLabeledStatement");
List<Label> labels = popList(labelCount);
enterLocalScope(null, scope.createNestedLabelScope());
- LabelTarget target =
- new LabelTarget(member, functionNestingLevel, token.charOffset);
+ LabelTarget target = new LabelTarget<Statement>(
+ member, functionNestingLevel, token.charOffset);
for (Label label in labels) {
scope.declareLabel(label.name, target);
}
@@ -3279,13 +3282,13 @@
if (kernelStatement is! LabeledStatement) {
kernelStatement = new ShadowLabeledStatement(kernelStatement);
}
- target.breakTarget.resolveBreaks(kernelStatement);
+ target.breakTarget.resolveBreaks(forest, kernelStatement);
}
if (target.continueTarget.hasUsers) {
if (kernelStatement is! LabeledStatement) {
kernelStatement = new ShadowLabeledStatement(kernelStatement);
}
- target.continueTarget.resolveContinues(kernelStatement);
+ target.continueTarget.resolveContinues(forest, kernelStatement);
}
push(kernelStatement);
}
@@ -3315,17 +3318,14 @@
Expression condition = popForValue();
JumpTarget continueTarget = exitContinueTarget();
JumpTarget breakTarget = exitBreakTarget();
- kernel.Statement kernelBody = toKernelStatement(body);
if (continueTarget.hasUsers) {
- kernelBody = new ShadowLabeledStatement(kernelBody);
- continueTarget.resolveContinues(kernelBody);
+ body = forest.syntheticLabeledStatement(body);
+ continueTarget.resolveContinues(forest, body);
}
- kernel.Statement result =
- new ShadowWhileStatement(toKernelExpression(condition), kernelBody)
- ..fileOffset = whileKeyword.charOffset;
+ Statement result = forest.whileStatement(whileKeyword, condition, body);
if (breakTarget.hasUsers) {
- result = new ShadowLabeledStatement(result);
- breakTarget.resolveBreaks(result);
+ result = forest.syntheticLabeledStatement(result);
+ breakTarget.resolveBreaks(forest, result);
}
exitLoopOrSwitch(result);
}
@@ -3500,9 +3500,9 @@
..fileOffset = switchKeyword.charOffset;
if (target.hasUsers) {
result = new ShadowLabeledStatement(result);
- target.resolveBreaks(result);
+ target.resolveBreaks(forest, result);
}
- exitLoopOrSwitch(result);
+ exitLoopOrSwitch(toStatement(result));
}
@override
@@ -3516,7 +3516,7 @@
for (Label label in labels) {
JumpTarget target = switchScope.lookupLabel(label.name);
if (target != null) {
- target.resolveGotos(current);
+ target.resolveGotos(forest, current);
}
}
}
@@ -4442,8 +4442,8 @@
}
}
-class JumpTarget extends Builder {
- final List<kernel.Statement> users = <kernel.Statement>[];
+class JumpTarget<Statement> extends Builder {
+ final List<Statement> users = <Statement>[];
final JumpTargetKind kind;
@@ -4461,41 +4461,44 @@
bool get hasUsers => users.isNotEmpty;
- void addBreak(BreakStatement statement) {
+ void addBreak(Statement statement) {
assert(isBreakTarget);
users.add(statement);
}
- void addContinue(BreakStatement statement) {
+ void addContinue(Statement statement) {
assert(isContinueTarget);
users.add(statement);
}
- void addGoto(ContinueSwitchStatement statement) {
+ void addGoto(Statement statement) {
assert(isGotoTarget);
users.add(statement);
}
- void resolveBreaks(LabeledStatement target) {
+ void resolveBreaks(
+ Forest<dynamic, Statement, dynamic, dynamic> forest, Statement target) {
assert(isBreakTarget);
- for (BreakStatement user in users) {
- user.target = target;
+ for (Statement user in users) {
+ forest.resolveBreak(target, user);
}
users.clear();
}
- void resolveContinues(LabeledStatement target) {
+ void resolveContinues(
+ Forest<dynamic, Statement, dynamic, dynamic> forest, Statement target) {
assert(isContinueTarget);
- for (BreakStatement user in users) {
- user.target = target;
+ for (Statement user in users) {
+ forest.resolveContinue(target, user);
}
users.clear();
}
- void resolveGotos(SwitchCase target) {
+ void resolveGotos(
+ Forest<dynamic, Statement, dynamic, dynamic> forest, Object target) {
assert(isGotoTarget);
- for (ContinueSwitchStatement user in users) {
- user.target = target;
+ for (Statement user in users) {
+ forest.resolveContinueInSwitch(target, user);
}
users.clear();
}
@@ -4504,7 +4507,7 @@
String get fullNameForErrors => "<jump-target>";
}
-class LabelTarget extends Builder implements JumpTarget {
+class LabelTarget<Statement> extends Builder implements JumpTarget<Statement> {
final JumpTarget breakTarget;
final JumpTarget continueTarget;
@@ -4512,15 +4515,15 @@
final int functionNestingLevel;
LabelTarget(MemberBuilder member, this.functionNestingLevel, int charOffset)
- : breakTarget = new JumpTarget(
+ : breakTarget = new JumpTarget<Statement>(
JumpTargetKind.Break, functionNestingLevel, member, charOffset),
- continueTarget = new JumpTarget(
+ continueTarget = new JumpTarget<Statement>(
JumpTargetKind.Continue, functionNestingLevel, member, charOffset),
super(member, charOffset, member.fileUri);
bool get hasUsers => breakTarget.hasUsers || continueTarget.hasUsers;
- List<kernel.Statement> get users => unsupported("users", charOffset, fileUri);
+ List<Statement> get users => unsupported("users", charOffset, fileUri);
JumpTargetKind get kind => unsupported("kind", charOffset, fileUri);
@@ -4530,27 +4533,30 @@
bool get isGotoTarget => false;
- void addBreak(BreakStatement statement) {
+ void addBreak(Statement statement) {
breakTarget.addBreak(statement);
}
- void addContinue(BreakStatement statement) {
+ void addContinue(Statement statement) {
continueTarget.addContinue(statement);
}
- void addGoto(ContinueSwitchStatement statement) {
+ void addGoto(Statement statement) {
unsupported("addGoto", charOffset, fileUri);
}
- void resolveBreaks(LabeledStatement target) {
- breakTarget.resolveBreaks(target);
+ void resolveBreaks(
+ Forest<dynamic, Statement, dynamic, dynamic> forest, Statement target) {
+ breakTarget.resolveBreaks(forest, target);
}
- void resolveContinues(LabeledStatement target) {
- continueTarget.resolveContinues(target);
+ void resolveContinues(
+ Forest<dynamic, Statement, dynamic, dynamic> forest, Statement target) {
+ continueTarget.resolveContinues(forest, target);
}
- void resolveGotos(SwitchCase target) {
+ void resolveGotos(
+ Forest<dynamic, Statement, dynamic, dynamic> forest, Object target) {
unsupported("resolveGotos", charOffset, fileUri);
}
diff --git a/pkg/front_end/lib/src/fasta/kernel/fangorn.dart b/pkg/front_end/lib/src/fasta/kernel/fangorn.dart
index aff0f1b..aea6f0c 100644
--- a/pkg/front_end/lib/src/fasta/kernel/fangorn.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/fangorn.dart
@@ -9,18 +9,22 @@
import 'package:kernel/ast.dart'
show
Arguments,
+ BreakStatement,
Block,
Catch,
+ ContinueSwitchStatement,
DartType,
EmptyStatement,
Expression,
ExpressionStatement,
InvalidExpression,
+ LabeledStatement,
Let,
LibraryDependency,
MapEntry,
NamedExpression,
Statement,
+ SwitchCase,
ThisExpression,
TreeNode,
VariableDeclaration,
@@ -47,6 +51,7 @@
ShadowIntLiteral,
ShadowIsExpression,
ShadowIsNotExpression,
+ ShadowLabeledStatement,
ShadowListLiteral,
ShadowLoadLibrary,
ShadowMapLiteral,
@@ -62,6 +67,7 @@
ShadowTryCatch,
ShadowTryFinally,
ShadowTypeLiteral,
+ ShadowWhileStatement,
ShadowYieldStatement;
import 'forest.dart' show Forest;
@@ -289,6 +295,11 @@
}
@override
+ Statement syntheticLabeledStatement(Statement statement) {
+ return new ShadowLabeledStatement(statement);
+ }
+
+ @override
Expression thisExpression(Token token) {
return new ShadowThisExpression()..fileOffset = offsetForToken(token);
}
@@ -338,6 +349,13 @@
}
@override
+ Statement whileStatement(
+ Token whileKeyword, Expression condition, Statement body) {
+ return new ShadowWhileStatement(condition, body)
+ ..fileOffset = whileKeyword.charOffset;
+ }
+
+ @override
Statement yieldStatement(
Token yieldKeyword, Token star, Expression expression, Token semicolon) {
return new ShadowYieldStatement(expression, isYieldStar: star != null)
@@ -373,6 +391,22 @@
@override
bool isVariablesDeclaration(Object node) => node is _VariablesDeclaration;
+
+ @override
+ void resolveBreak(LabeledStatement target, BreakStatement user) {
+ user.target = target;
+ }
+
+ @override
+ void resolveContinue(LabeledStatement target, BreakStatement user) {
+ user.target = target;
+ }
+
+ @override
+ void resolveContinueInSwitch(
+ SwitchCase target, ContinueSwitchStatement user) {
+ user.target = target;
+ }
}
class _VariablesDeclaration extends Statement {
diff --git a/pkg/front_end/lib/src/fasta/kernel/forest.dart b/pkg/front_end/lib/src/fasta/kernel/forest.dart
index 07e10b2..1547c7f 100644
--- a/pkg/front_end/lib/src/fasta/kernel/forest.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/forest.dart
@@ -4,10 +4,11 @@
library fasta.forest;
-import 'body_builder.dart' show Identifier;
// TODO(ahe): Remove this import.
import 'package:kernel/ast.dart' as kernel show Arguments, DartType;
+import 'body_builder.dart' show Identifier;
+
/// A tree factory.
///
/// For now, the [Location] is always a token.
@@ -175,6 +176,11 @@
Expression stringConcatenationExpression(
List<Expression> expressions, Location location);
+ /// The given [statement] is being used as the target of either a break or
+ /// continue statement. Return the statement that should be used as the actual
+ /// target.
+ Statement syntheticLabeledStatement(Statement statement);
+
Expression thisExpression(Location location);
/// Return a representation of a throw expression consisting of the
@@ -199,6 +205,11 @@
Statement wrapVariables(Statement statement);
+ /// Return a representation of a while statement introduced by the
+ /// [whileKeyword] and consisting of the given [condition] and [body].
+ Statement whileStatement(
+ Location whileKeyword, covariant Expression condition, Statement body);
+
/// Return a representation of a yield statement consisting of the
/// [yieldKeyword], [star], [expression], and [semicolon]. The [star] is null
/// when no star was included in the source code.
@@ -213,6 +224,19 @@
bool isVariablesDeclaration(Object node);
+ /// Record that the [user] (a break statement) is associated with the [target]
+ /// statement.
+ void resolveBreak(covariant Statement target, covariant Statement user);
+
+ /// Record that the [user] (a continue statement) is associated with the
+ /// [target] statement.
+ void resolveContinue(covariant Statement target, covariant Statement user);
+
+ /// Record that the [user] (a continue statement inside a switch case) is
+ /// associated with the [target] statement.
+ void resolveContinueInSwitch(
+ covariant Object target, covariant Statement user);
+
// TODO(ahe): Remove this method when all users are moved here.
kernel.Arguments castArguments(Arguments arguments) {
dynamic a = arguments;
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 0599d3d..a6d0c8c 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
@@ -107,5 +107,4 @@
ShadowVariableAssignment,
ShadowVariableDeclaration,
ShadowVariableGet,
- ShadowWhileStatement,
ShadowYieldStatement;