mirror of
https://github.com/dart-lang/sdk
synced 2024-09-18 20:31:21 +00:00
dart2dart: Support for break in loops.
Break is supported by collecting all the exits from the loop body and processing them after the loop body is translated. If there are any, a join-point continuation for all the exits is added. This continuation should be in the scope of the nearest common ancestor of all the exits --- which is the scope of the condition since the branch on the condition always has an exit. BUG= R=floitsch@google.com, sigurdm@google.com Review URL: https://codereview.chromium.org//469263002 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@39290 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
parent
b0a1da2971
commit
ee5635056f
|
@ -137,12 +137,19 @@ class _GetterElements {
|
|||
_GetterElements({this.result, this.index, this.receiver}) ;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
/// A mapping from variable elements to their compile-time values.
|
||||
///
|
||||
/// Map elements denoted by parameters and local variables to the
|
||||
/// [ir.Primitive] that is their value. Parameters and locals are
|
||||
/// assigned indexes which can be used to refer to them.
|
||||
class Environment {
|
||||
/// A map from elements to their environment index.
|
||||
final Map<Element, int> variable2index;
|
||||
|
||||
/// A reverse map from environment indexes to the variable.
|
||||
final List<Element> index2variable;
|
||||
|
||||
/// A map from environment indexes to their value.
|
||||
final List<ir.Primitive> index2value;
|
||||
|
||||
Environment.empty()
|
||||
|
@ -150,6 +157,9 @@ class Environment {
|
|||
index2variable = <Element>[],
|
||||
index2value = <ir.Primitive>[];
|
||||
|
||||
/// Construct an environment that is a copy of another one.
|
||||
///
|
||||
/// The mapping from elements to indexes is shared, not copied.
|
||||
Environment.from(Environment other)
|
||||
: variable2index = other.variable2index,
|
||||
index2variable = new List<Element>.from(other.index2variable),
|
||||
|
@ -202,6 +212,38 @@ class Environment {
|
|||
}
|
||||
}
|
||||
|
||||
/// A class to collect breaks or continues.
|
||||
///
|
||||
/// When visiting a potential target of breaks or continues, any breaks or
|
||||
/// continues are collected by a JumpCollector and processed later, on demand.
|
||||
/// The site of the break or continue is represented by a continuation
|
||||
/// invocation that will have its target and arguments filled in later.
|
||||
///
|
||||
/// The environment of the builder at that point is captured and should not
|
||||
/// be subsequently mutated until the jump is resolved.
|
||||
class JumpCollector {
|
||||
final JumpTarget target;
|
||||
final List<ir.InvokeContinuation> _invocations = <ir.InvokeContinuation>[];
|
||||
final List<Environment> _environments = <Environment>[];
|
||||
|
||||
JumpCollector(this.target);
|
||||
|
||||
bool get isEmpty => _invocations.isEmpty;
|
||||
int get length => _invocations.length;
|
||||
List<ir.InvokeContinuation> get invocations => _invocations;
|
||||
List<Environment> get environments => _environments;
|
||||
|
||||
void addJump(IrBuilder builder) {
|
||||
ir.InvokeContinuation invoke = new ir.InvokeContinuation.uninitialized();
|
||||
builder.add(invoke);
|
||||
_invocations.add(invoke);
|
||||
_environments.add(builder.environment);
|
||||
builder.current = null;
|
||||
// TODO(kmillikin): Can we set builder.environment to null to make it
|
||||
// less likely to mutate it?
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A tree visitor that builds [IrNodes]. The visit methods add statements using
|
||||
* to the [builder] and return the last added statement for trees that represent
|
||||
|
@ -260,6 +302,9 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
|
|||
/// A map from variable indexes to their values.
|
||||
Environment environment;
|
||||
|
||||
/// A stack of collectors for breaks.
|
||||
final List<JumpCollector> breakCollectors;
|
||||
|
||||
ConstExpBuilder constantBuilder;
|
||||
|
||||
final List<ConstDeclaration> localConstants;
|
||||
|
@ -272,6 +317,7 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
|
|||
: returnContinuation = new ir.Continuation.retrn(),
|
||||
parameters = <ir.Parameter>[],
|
||||
environment = new Environment.empty(),
|
||||
breakCollectors = <JumpCollector>[],
|
||||
localConstants = <ConstDeclaration>[],
|
||||
closureLocals = new DetectClosureVariables(elements),
|
||||
super(elements, compiler) {
|
||||
|
@ -289,6 +335,7 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
|
|||
returnContinuation = parent.returnContinuation,
|
||||
parameters = <ir.Parameter>[],
|
||||
environment = new Environment.from(parent.environment),
|
||||
breakCollectors = parent.breakCollectors,
|
||||
constantBuilder = parent.constantBuilder,
|
||||
localConstants = parent.localConstants,
|
||||
currentFunction = parent.currentFunction,
|
||||
|
@ -308,6 +355,7 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
|
|||
returnContinuation = parent.returnContinuation,
|
||||
parameters = <ir.Parameter>[],
|
||||
environment = new Environment.empty(),
|
||||
breakCollectors = parent.breakCollectors,
|
||||
constantBuilder = parent.constantBuilder,
|
||||
localConstants = parent.localConstants,
|
||||
currentFunction = parent.currentFunction,
|
||||
|
@ -420,6 +468,23 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
|
|||
return null;
|
||||
}
|
||||
|
||||
// Build(BreakStatement L, C) = C[InvokeContinuation(...)]
|
||||
//
|
||||
// The continuation and arguments are filled in later after translating
|
||||
// the body containing the break.
|
||||
ir.Primitive visitBreakStatement(ast.BreakStatement node) {
|
||||
assert(isOpen);
|
||||
JumpTarget target = elements.getTargetOf(node);
|
||||
for (JumpCollector collector in breakCollectors) {
|
||||
if (target == collector.target) {
|
||||
collector.addJump(this);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
compiler.internalError(node, "'break' target not found");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Build(EmptyStatement, C) = C
|
||||
ir.Primitive visitEmptyStatement(ast.EmptyStatement node) {
|
||||
assert(isOpen);
|
||||
|
@ -437,24 +502,24 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
|
|||
|
||||
/// Create a non-recursive join-point continuation.
|
||||
///
|
||||
/// Given the environment length at the join point and a list of open
|
||||
/// contexts that should reach the join point, create a join-point
|
||||
/// Given the environment length at the join point and a list of
|
||||
/// jumps that should reach the join point, create a join-point
|
||||
/// continuation. The join-point continuation has a parameter for each
|
||||
/// variable that has different values reaching on different paths.
|
||||
///
|
||||
/// The holes in the contexts are filled with [ir.InvokeContinuation]
|
||||
/// expressions passing the appropriate arguments.
|
||||
/// The jumps are uninitialized [ir.InvokeContinuation] expressions.
|
||||
/// They are filled in with the target continuation and appropriate
|
||||
/// arguments.
|
||||
///
|
||||
/// As a side effect, the environment of this builder is updated to include
|
||||
/// the join-point continuation parameters.
|
||||
ir.Continuation createJoin(int environmentLength,
|
||||
List<IrBuilder> contexts) {
|
||||
assert(contexts.length >= 2);
|
||||
ir.Continuation createJoin(int environmentLength, JumpCollector jumps) {
|
||||
assert(jumps.length >= 2);
|
||||
|
||||
// Compute which values are identical on all paths reaching the join.
|
||||
// Handle the common case of a pair of contexts efficiently.
|
||||
Environment first = contexts[0].environment;
|
||||
Environment second = contexts[1].environment;
|
||||
Environment first = jumps.environments[0];
|
||||
Environment second = jumps.environments[1];
|
||||
assert(environmentLength <= first.length);
|
||||
assert(environmentLength <= second.length);
|
||||
assert(first.sameDomain(environmentLength, second));
|
||||
|
@ -479,10 +544,10 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
|
|||
for (int i = 0; i < environmentLength; ++i) {
|
||||
ir.Primitive candidate = common[i];
|
||||
if (candidate == null) continue;
|
||||
for (IrBuilder current in contexts.skip(2)) {
|
||||
assert(environmentLength <= current.environment.length);
|
||||
assert(first.sameDomain(environmentLength, current.environment));
|
||||
if (candidate != current.environment[i]) {
|
||||
for (Environment current in jumps.environments.skip(2)) {
|
||||
assert(environmentLength <= current.length);
|
||||
assert(first.sameDomain(environmentLength, current));
|
||||
if (candidate != current[i]) {
|
||||
common[i] = null;
|
||||
++parameterCount;
|
||||
break;
|
||||
|
@ -492,40 +557,49 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
|
|||
}
|
||||
}
|
||||
|
||||
// Create the join point continuation.
|
||||
List<ir.Parameter> parameters = <ir.Parameter>[];
|
||||
parameters.length = parameterCount;
|
||||
int index = 0;
|
||||
for (int i = 0; i < environmentLength; ++i) {
|
||||
if (common[i] == null) {
|
||||
ir.Parameter parameter = new ir.Parameter(first.index2variable[i]);
|
||||
parameters[index++] = parameter;
|
||||
if (i < environment.length) {
|
||||
// The variable is bound to the join-point parameter in the
|
||||
// continuation. Variables outside the range of the environment are
|
||||
// 'phantom' variables used for the values of expressions like
|
||||
// &&, ||, and ?:.
|
||||
environment.index2value[i] = parameter;
|
||||
}
|
||||
parameters[index++] = new ir.Parameter(first.index2variable[i]);
|
||||
}
|
||||
}
|
||||
assert(index == parameterCount);
|
||||
ir.Continuation join = new ir.Continuation(parameters);
|
||||
|
||||
// Plug all the contexts with continuation invocations.
|
||||
for (IrBuilder context in contexts) {
|
||||
// Passing `this` as one of the contexts will not do the right thing
|
||||
// (this.environment has already been mutated).
|
||||
assert(context != this);
|
||||
List<ir.Primitive> arguments = <ir.Primitive>[];
|
||||
// Fill in all the continuation invocations.
|
||||
for (int i = 0; i < jumps.length; ++i) {
|
||||
Environment currentEnvironment = jumps.environments[i];
|
||||
ir.InvokeContinuation invoke = jumps.invocations[i];
|
||||
// Sharing this.environment with one of the invocations will not do
|
||||
// the right thing (this.environment has already been mutated).
|
||||
List<ir.Reference> arguments = <ir.Reference>[];
|
||||
arguments.length = parameterCount;
|
||||
int index = 0;
|
||||
for (int i = 0; i < environmentLength; ++i) {
|
||||
if (common[i] == null) {
|
||||
arguments[index++] = context.environment[i];
|
||||
arguments[index++] = new ir.Reference(currentEnvironment[i]);
|
||||
}
|
||||
}
|
||||
context.add(new ir.InvokeContinuation(join, arguments));
|
||||
context.current = null;
|
||||
invoke.continuation = new ir.Reference(join);
|
||||
invoke.arguments = arguments;
|
||||
}
|
||||
|
||||
// Mutate this.environment to be the environment at the join point. Do
|
||||
// this after adding the continuation invocations, because this.environment
|
||||
// might be collected by the jump collector and so the old environment
|
||||
// values are needed for the continuation invocation.
|
||||
//
|
||||
// Iterate to environment.length because environmentLength includes values
|
||||
// outside the environment which are 'phantom' variables used for the
|
||||
// values of expressions like &&, ||, and ?:.
|
||||
index = 0;
|
||||
for (int i = 0; i < environment.length; ++i) {
|
||||
if (common[i] == null) {
|
||||
environment.index2value[i] = parameters[index++];
|
||||
}
|
||||
}
|
||||
|
||||
return join;
|
||||
|
@ -561,17 +635,23 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
|
|||
}
|
||||
}
|
||||
|
||||
// For loops use three named continuations: the entry to the condition,
|
||||
// the entry to the body, and the loop exit (break). The CPS translation
|
||||
// of [[for (initializer; condition; update) body; successor]] is:
|
||||
// For loops use four named continuations: the entry to the condition,
|
||||
// the entry to the body, the loop exit, and the loop successor (break).
|
||||
// The CPS translation of
|
||||
// [[for (initializer; condition; update) body; successor]] is:
|
||||
//
|
||||
// [[initializer]];
|
||||
// let cont loop(x, ...) =
|
||||
// let prim cond = [[condition]] in
|
||||
// let cont exit() = [[successor]] in
|
||||
// let cont break() = [[successor]] in
|
||||
// let cont exit() = break(v, ...) in
|
||||
// let cont body() = [[body]]; [[update]]; loop(v, ...) in
|
||||
// branch cond (body, exit) in
|
||||
// loop(v, ...)
|
||||
//
|
||||
// If there are no breaks in the body, the break continuation is inlined
|
||||
// in the exit continuation (i.e., the translation of the successor
|
||||
// statement occurs in the exit continuation).
|
||||
|
||||
if (node.initializer != null) visit(node.initializer);
|
||||
|
||||
|
@ -585,23 +665,37 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
|
|||
condition = condBuilder.visit(node.condition);
|
||||
}
|
||||
|
||||
JumpCollector breakCollector =
|
||||
new JumpCollector(elements.getTargetDefinition(node));
|
||||
breakCollectors.add(breakCollector);
|
||||
IrBuilder bodyBuilder = new IrBuilder.delimited(condBuilder);
|
||||
bodyBuilder.visit(node.body);
|
||||
for (ast.Node n in node.update) {
|
||||
if (!bodyBuilder.isOpen) break;
|
||||
bodyBuilder.visit(n);
|
||||
}
|
||||
assert(breakCollectors.last == breakCollector);
|
||||
breakCollectors.removeLast();
|
||||
|
||||
// Create body entry and loop exit continuations and a join-point
|
||||
// continuation if control flow reaches the end of the body (update).
|
||||
// Create body entry and loop exit continuations and a branch to them.
|
||||
ir.Continuation bodyContinuation = new ir.Continuation([]);
|
||||
ir.Continuation exitContinuation = new ir.Continuation([]);
|
||||
condBuilder.add(
|
||||
ir.LetCont branch =
|
||||
new ir.LetCont(exitContinuation,
|
||||
new ir.LetCont(bodyContinuation,
|
||||
new ir.Branch(new ir.IsTrue(condition),
|
||||
bodyContinuation,
|
||||
exitContinuation))));
|
||||
exitContinuation)));
|
||||
// If there are breaks in the body, then there must be a join-point
|
||||
// continuation for the normal exit and the breaks.
|
||||
ir.LetCont letJoin;
|
||||
if (breakCollector.isEmpty) {
|
||||
condBuilder.add(branch);
|
||||
} else {
|
||||
letJoin = new ir.LetCont(null, branch);
|
||||
condBuilder.add(letJoin);
|
||||
condBuilder.current = branch;
|
||||
}
|
||||
List<ir.Parameter> parameters = condBuilder.parameters;
|
||||
ir.Continuation loopContinuation = new ir.Continuation(parameters);
|
||||
if (bodyBuilder.isOpen) {
|
||||
|
@ -613,8 +707,16 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
|
|||
add(new ir.LetCont(loopContinuation,
|
||||
new ir.InvokeContinuation(loopContinuation,
|
||||
environment.index2value)));
|
||||
current = condBuilder.current;
|
||||
environment = condBuilder.environment;
|
||||
if (letJoin == null) {
|
||||
current = condBuilder.current;
|
||||
environment = condBuilder.environment;
|
||||
} else {
|
||||
current = branch;
|
||||
environment = condBuilder.environment;
|
||||
breakCollector.addJump(this);
|
||||
letJoin.continuation = createJoin(environment.length, breakCollector);
|
||||
current = letJoin;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -647,8 +749,10 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
|
|||
// There is a join-point continuation. Build the term
|
||||
// 'let cont join(x, ...) = [] in Result' and plug invocations of the
|
||||
// join-point continuation into the then and else continuations.
|
||||
joinContinuation =
|
||||
createJoin(environment.length, [thenBuilder, elseBuilder]);
|
||||
JumpCollector jumps = new JumpCollector(null);
|
||||
jumps.addJump(thenBuilder);
|
||||
jumps.addJump(elseBuilder);
|
||||
joinContinuation = createJoin(environment.length, jumps);
|
||||
result = new ir.LetCont(joinContinuation, result);
|
||||
}
|
||||
|
||||
|
@ -678,36 +782,62 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
|
|||
return null;
|
||||
}
|
||||
|
||||
ir.Primitive visitLabeledStatement(ast.LabeledStatement node) {
|
||||
ast.Statement body = node.statement;
|
||||
return body is ast.Loop
|
||||
? visit(body)
|
||||
: giveup(node, 'labeled statement');
|
||||
}
|
||||
|
||||
ir.Primitive visitWhile(ast.While node) {
|
||||
assert(isOpen);
|
||||
// While loops use three named continuations: the entry to the body,
|
||||
// the loop exit (break), and the loop back edge (continue).
|
||||
// While loops use four named continuations: the entry to the body, the
|
||||
// loop exit, the loop back edge (continue), and the loop exit (break).
|
||||
// The CPS translation of [[while (condition) body; successor]] is:
|
||||
//
|
||||
// let cont loop(x, ...) =
|
||||
// let prim cond = [[condition]] in
|
||||
// let cont exit() = [[successor]] in
|
||||
// let cont break() = [[successor]] in
|
||||
// let cont exit() = break(v, ...) in
|
||||
// let cont body() = [[body]]; continue(v, ...) in
|
||||
// branch cond (body, exit) in
|
||||
// loop(v, ...)
|
||||
//
|
||||
// If there are no breaks in the body, the break continuation is inlined
|
||||
// in the exit continuation (i.e., the translation of the successor
|
||||
// statement occurs in the exit continuation).
|
||||
|
||||
// The condition and body are delimited.
|
||||
IrBuilder condBuilder = new IrBuilder.recursive(this);
|
||||
ir.Primitive condition = condBuilder.visit(node.condition);
|
||||
|
||||
JumpCollector breakCollector =
|
||||
new JumpCollector(elements.getTargetDefinition(node));
|
||||
breakCollectors.add(breakCollector);
|
||||
IrBuilder bodyBuilder = new IrBuilder.delimited(condBuilder);
|
||||
bodyBuilder.visit(node.body);
|
||||
assert(breakCollectors.last == breakCollector);
|
||||
breakCollectors.removeLast();
|
||||
|
||||
// Create body entry and loop exit continuations and a join-point
|
||||
// continuation if control flow reaches the end of the body.
|
||||
// Create body entry and loop exit continuations and a branch to them.
|
||||
ir.Continuation bodyContinuation = new ir.Continuation([]);
|
||||
ir.Continuation exitContinuation = new ir.Continuation([]);
|
||||
condBuilder.add(
|
||||
ir.LetCont branch =
|
||||
new ir.LetCont(exitContinuation,
|
||||
new ir.LetCont(bodyContinuation,
|
||||
new ir.Branch(new ir.IsTrue(condition),
|
||||
bodyContinuation,
|
||||
exitContinuation))));
|
||||
exitContinuation)));
|
||||
// If there are breaks in the body, then there must be a join-point
|
||||
// continuation for the normal exit and the breaks.
|
||||
ir.LetCont letJoin;
|
||||
if (breakCollector.isEmpty) {
|
||||
condBuilder.add(branch);
|
||||
} else {
|
||||
letJoin = new ir.LetCont(null, branch);
|
||||
condBuilder.add(letJoin);
|
||||
condBuilder.current = branch;
|
||||
}
|
||||
List<ir.Parameter> parameters = condBuilder.parameters;
|
||||
ir.Continuation loopContinuation = new ir.Continuation(parameters);
|
||||
if (bodyBuilder.isOpen) {
|
||||
|
@ -719,8 +849,16 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
|
|||
add(new ir.LetCont(loopContinuation,
|
||||
new ir.InvokeContinuation(loopContinuation,
|
||||
environment.index2value)));
|
||||
current = condBuilder.current;
|
||||
environment = condBuilder.environment;
|
||||
if (letJoin == null) {
|
||||
current = condBuilder.current;
|
||||
environment = condBuilder.environment;
|
||||
} else {
|
||||
current = branch;
|
||||
environment = condBuilder.environment;
|
||||
breakCollector.addJump(this);
|
||||
letJoin.continuation = createJoin(environment.length, breakCollector);
|
||||
current = letJoin;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -804,8 +942,11 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
|
|||
assert(environment.length == elseBuilder.environment.length);
|
||||
thenBuilder.environment.extend(null, thenValue);
|
||||
elseBuilder.environment.extend(null, elseValue);
|
||||
JumpCollector jumps = new JumpCollector(null);
|
||||
jumps.addJump(thenBuilder);
|
||||
jumps.addJump(elseBuilder);
|
||||
ir.Continuation joinContinuation =
|
||||
createJoin(environment.length + 1, [thenBuilder, elseBuilder]);
|
||||
createJoin(environment.length + 1, jumps);
|
||||
|
||||
// Build the term
|
||||
// let cont join(x, ..., result) = [] in
|
||||
|
@ -1155,8 +1296,12 @@ class IrBuilder extends ResolvedVisitor<ir.Primitive> {
|
|||
|
||||
// Wire up two continuations for the left subexpression, two continuations
|
||||
// for the right subexpression, and a three-way join continuation.
|
||||
ir.Continuation joinContinuation = createJoin(environment.length + 1,
|
||||
[emptyBuilder, rightTrueBuilder, rightFalseBuilder]);
|
||||
JumpCollector jumps = new JumpCollector(null);
|
||||
jumps.addJump(emptyBuilder);
|
||||
jumps.addJump(rightTrueBuilder);
|
||||
jumps.addJump(rightFalseBuilder);
|
||||
ir.Continuation joinContinuation =
|
||||
createJoin(environment.length + 1, jumps);
|
||||
ir.Continuation leftTrueContinuation = new ir.Continuation([]);
|
||||
ir.Continuation leftFalseContinuation = new ir.Continuation([]);
|
||||
ir.Continuation rightTrueContinuation = new ir.Continuation([]);
|
||||
|
|
|
@ -12,7 +12,6 @@ import '../elements/elements.dart';
|
|||
import '../universe/universe.dart' show Selector, SelectorKind;
|
||||
import '../dart_types.dart' show DartType, GenericType;
|
||||
import 'const_expression.dart';
|
||||
import '../helpers/helpers.dart';
|
||||
|
||||
abstract class Node {
|
||||
static int hashCount = 0;
|
||||
|
@ -132,13 +131,13 @@ class LetPrim extends Expression implements InteriorNode {
|
|||
/// During one-pass construction a LetCont with an empty continuation body is
|
||||
/// used to represent the one-level context 'let cont k(v) = [] in E'.
|
||||
class LetCont extends Expression implements InteriorNode {
|
||||
final Continuation continuation;
|
||||
Continuation continuation;
|
||||
Expression body;
|
||||
|
||||
LetCont(this.continuation, this.body);
|
||||
|
||||
Expression plug(Expression expr) {
|
||||
assert(continuation.body == null);
|
||||
assert(continuation != null && continuation.body == null);
|
||||
return continuation.body = expr;
|
||||
}
|
||||
|
||||
|
@ -387,8 +386,8 @@ class DeclareFunction extends Expression implements InteriorNode {
|
|||
|
||||
/// Invoke a continuation in tail position.
|
||||
class InvokeContinuation extends Expression {
|
||||
final Reference continuation;
|
||||
final List<Reference> arguments;
|
||||
Reference continuation;
|
||||
List<Reference> arguments;
|
||||
|
||||
// An invocation of a continuation is recursive if it occurs in the body of
|
||||
// the continuation itself.
|
||||
|
@ -404,6 +403,16 @@ class InvokeContinuation extends Expression {
|
|||
if (recursive) cont.isRecursive = true;
|
||||
}
|
||||
|
||||
/// A continuation invocation whose target and arguments will be filled
|
||||
/// in later.
|
||||
///
|
||||
/// Used as a placeholder for a jump whose target is not yet created
|
||||
/// (e.g., in the translation of break and continue).
|
||||
InvokeContinuation.uninitialized({recursive: false})
|
||||
: continuation = null,
|
||||
arguments = null,
|
||||
isRecursive = recursive;
|
||||
|
||||
accept(Visitor visitor) => visitor.visitInvokeContinuation(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -415,7 +415,7 @@ class ASTEmitter extends tree.Visitor<dynamic, Expression> {
|
|||
Statement body = new Block(statementBuffer);
|
||||
Statement statement = new While(new Literal(new dart2js.TrueConstant()),
|
||||
body);
|
||||
if (usedLabels.remove(stmt.label.name)) {
|
||||
if (usedLabels.remove(stmt.label)) {
|
||||
statement = new LabeledStatement(stmt.label.name, statement);
|
||||
}
|
||||
savedBuffer.add(statement);
|
||||
|
@ -436,7 +436,7 @@ class ASTEmitter extends tree.Visitor<dynamic, Expression> {
|
|||
Statement body = new Block(statementBuffer);
|
||||
Statement statement;
|
||||
statement = new While(condition, body);
|
||||
if (usedLabels.remove(stmt.label.name)) {
|
||||
if (usedLabels.remove(stmt.label)) {
|
||||
statement = new LabeledStatement(stmt.label.name, statement);
|
||||
}
|
||||
savedBuffer.add(statement);
|
||||
|
|
Loading…
Reference in a new issue