diff --git a/pkg/kernel/lib/interpreter/interpreter.dart b/pkg/kernel/lib/interpreter/interpreter.dart index 6d88dd25abc..2c03f2512c2 100644 --- a/pkg/kernel/lib/interpreter/interpreter.dart +++ b/pkg/kernel/lib/interpreter/interpreter.dart @@ -317,7 +317,8 @@ class State { continuation = null; State withBreak(Statement stmt, Environment env) { - Label breakLabels = new Label(stmt, env, continuation, labels); + var cont = new BreakBK(continuation, env); + Label breakLabels = new Label(stmt, cont, labels); return new State( breakLabels, exceptionComponents, returnContinuation, continuation); } @@ -344,18 +345,23 @@ class State { /// enclosing label. class Label { final LabeledStatement statement; - final Environment environment; - final StatementContinuation continuation; + final BreakContinuation continuation; final Label enclosingLabel; - Label( - this.statement, this.environment, this.continuation, this.enclosingLabel); + Label(this.statement, this.continuation, this.enclosingLabel); Label lookupLabel(LabeledStatement s) { if (identical(s, statement)) return this; assert(enclosingLabel != null); return enclosingLabel.lookupLabel(s); } + + // Recursively install finally break to all labels. + Label withFinalizer(Statement finalizer, Environment env, State state) { + var label = enclosingLabel?.withFinalizer(finalizer, env, state); + var finallyCont = new FinallyBK(finalizer, env, state, continuation); + return new Label(statement, finallyCont, label); + } } // ------------------------------------------------------------------------ @@ -456,6 +462,50 @@ class ThrowConfiguration extends Configuration { Configuration step(StatementExecuter _) => handler(exception, stacktrace); } +class BreakConfiguration extends Configuration { + final BreakContinuation continuation; + + BreakConfiguration(this.continuation); + + Configuration step(StatementExecuter _) => continuation(); +} + +abstract class BreakContinuation extends Continuation { + Configuration call(); +} + +class BreakBK extends BreakContinuation { + final StatementContinuation continuation; + final Environment environment; + + BreakBK(this.continuation, this.environment); + + Configuration call() => new ForwardConfiguration(continuation, environment); +} + +class FinallyBK extends BreakContinuation { + final Statement finalizer; + final Environment environment; + final State state; + final BreakContinuation continuation; + + FinallyBK(this.finalizer, this.environment, this.state, this.continuation); + + Configuration call() { + var cont = new BreakSK(continuation); + return new ExecConfiguration( + finalizer, environment, state.withContinuation(cont)); + } +} + +class BreakSK extends StatementContinuation { + final BreakContinuation continuation; + + BreakSK(this.continuation); + + Configuration call(Environment _) => new BreakConfiguration(continuation); +} + // ------------------------------------------------------------------------ // Interpreter Expressions and Values // ------------------------------------------------------------------------ @@ -1341,21 +1391,16 @@ class CatchHandler extends ExceptionHandler { class FinallyHandler extends ExceptionHandler { final Statement finallyStatement; final Environment environment; - final Label labels; - final ExceptionComponents exceptionComponents; - final ExpressionContinuation expressionContinuation; - - FinallyHandler(this.finallyStatement, this.environment, this.labels, - this.exceptionComponents, this.expressionContinuation); + final State state; + FinallyHandler(this.finallyStatement, this.environment, this.state); Configuration call(Value exception, StackTrace stackTrace) { // A finally handler can't handle an exception, only execute the // corresponding finally statement and rethrow. var cont = - new RethrowSK(exceptionComponents.handler, exception, stackTrace); - var state = - new State(labels, exceptionComponents, expressionContinuation, cont); - return new ExecConfiguration(finallyStatement, environment, state); + new RethrowSK(state.exceptionComponents.handler, exception, stackTrace); + var newState = state.withContinuation(cont); + return new ExecConfiguration(finallyStatement, environment, newState); } } @@ -1364,7 +1409,7 @@ class FinallyHandler extends ExceptionHandler { // ------------------------------------------------------------------------ /// Represents the components for Exception handling. /// -/// It contains the list of exception handlers, a stack trace and optional +/// It contains the current of exception handler, a stack trace and optional /// components, current stacktrace and exception. class ExceptionComponents { final ExceptionHandler handler; @@ -1483,7 +1528,7 @@ class StatementExecuter Configuration visitBreakStatement( BreakStatement node, ExecConfiguration conf) { Label l = conf.state.lookupLabel(node.target); - return new ForwardConfiguration(l.continuation, l.environment); + return new BreakConfiguration(l.continuation); } Configuration visitWhileStatement( @@ -1517,22 +1562,30 @@ class StatementExecuter Configuration visitTryCatch(TryCatch node, ExecConfiguration conf) { var handler = new CatchHandler(node.catches, conf.environment, conf.state); - var handlers = new ExceptionComponents( + var exceptionComponents = new ExceptionComponents( handler, conf.state.exceptionComponents.stackTrace, conf.state.exceptionComponents.currentStackTrace, conf.state.exceptionComponents.currentException); - var state = conf.state.withException(handlers); + var state = conf.state.withException(exceptionComponents); return new ExecConfiguration(node.body, conf.environment, state); } Configuration visitTryFinally(TryFinally node, ExecConfiguration conf) { - // TODO(zhivkag): Add FinallyBreak to break labels. var cont = new FinallySK(node.finalizer, conf.environment, conf.state); var returnCont = new FinallyReturnEK(node.finalizer, conf.environment, conf.state); - return new ExecConfiguration(node.body, conf.environment, - conf.state.withContinuation(cont).withReturnContinuation(returnCont)); + var labels = conf.state.labels + ?.withFinalizer(node.finalizer, conf.environment, conf.state); + var handler = + new FinallyHandler(node.finalizer, conf.environment, conf.state); + var exceptionComponents = new ExceptionComponents( + handler, + conf.state.exceptionComponents.stackTrace, + conf.state.exceptionComponents.currentStackTrace, + conf.state.exceptionComponents.currentException); + var state = new State(labels, exceptionComponents, returnCont, cont); + return new ExecConfiguration(node.body, conf.environment, state); } Configuration visitVariableDeclaration( diff --git a/pkg/kernel/testcases/interpreter/break_test.dart b/pkg/kernel/testcases/interpreter/break_test.dart new file mode 100644 index 00000000000..cbb47194082 --- /dev/null +++ b/pkg/kernel/testcases/interpreter/break_test.dart @@ -0,0 +1,18 @@ +// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +main() { + int i = 0; + while (true) { + try { + if (i == 5) { + break; + } + } catch (e, _) {} finally { + print('Finally with i=$i'); + } + print(i); + i++; + } +} diff --git a/pkg/kernel/testcases/interpreter/break_test.dart.expect b/pkg/kernel/testcases/interpreter/break_test.dart.expect new file mode 100644 index 00000000000..70d3cbd299a --- /dev/null +++ b/pkg/kernel/testcases/interpreter/break_test.dart.expect @@ -0,0 +1,12 @@ +print(String: Finally with i=0) +print(int: 0) +print(String: Finally with i=1) +print(int: 1) +print(String: Finally with i=2) +print(int: 2) +print(String: Finally with i=3) +print(int: 3) +print(String: Finally with i=4) +print(int: 4) +if-then +print(String: Finally with i=5)