mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 12:24:24 +00:00
Add support for finalizer of TryFinally in labeled statements
When a break is encountered in the body of a TryFinally statement to an enclosing label, the finalizer statement of the TryFinally is executed. BUG= R=dmitryas@google.com Review-Url: https://codereview.chromium.org/2991113002 .
This commit is contained in:
parent
771415a7c0
commit
115232ada2
3 changed files with 105 additions and 22 deletions
|
@ -317,7 +317,8 @@ class State {
|
||||||
continuation = null;
|
continuation = null;
|
||||||
|
|
||||||
State withBreak(Statement stmt, Environment env) {
|
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(
|
return new State(
|
||||||
breakLabels, exceptionComponents, returnContinuation, continuation);
|
breakLabels, exceptionComponents, returnContinuation, continuation);
|
||||||
}
|
}
|
||||||
|
@ -344,18 +345,23 @@ class State {
|
||||||
/// enclosing label.
|
/// enclosing label.
|
||||||
class Label {
|
class Label {
|
||||||
final LabeledStatement statement;
|
final LabeledStatement statement;
|
||||||
final Environment environment;
|
final BreakContinuation continuation;
|
||||||
final StatementContinuation continuation;
|
|
||||||
final Label enclosingLabel;
|
final Label enclosingLabel;
|
||||||
|
|
||||||
Label(
|
Label(this.statement, this.continuation, this.enclosingLabel);
|
||||||
this.statement, this.environment, this.continuation, this.enclosingLabel);
|
|
||||||
|
|
||||||
Label lookupLabel(LabeledStatement s) {
|
Label lookupLabel(LabeledStatement s) {
|
||||||
if (identical(s, statement)) return this;
|
if (identical(s, statement)) return this;
|
||||||
assert(enclosingLabel != null);
|
assert(enclosingLabel != null);
|
||||||
return enclosingLabel.lookupLabel(s);
|
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);
|
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
|
// Interpreter Expressions and Values
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
@ -1341,21 +1391,16 @@ class CatchHandler extends ExceptionHandler {
|
||||||
class FinallyHandler extends ExceptionHandler {
|
class FinallyHandler extends ExceptionHandler {
|
||||||
final Statement finallyStatement;
|
final Statement finallyStatement;
|
||||||
final Environment environment;
|
final Environment environment;
|
||||||
final Label labels;
|
final State state;
|
||||||
final ExceptionComponents exceptionComponents;
|
|
||||||
final ExpressionContinuation expressionContinuation;
|
|
||||||
|
|
||||||
FinallyHandler(this.finallyStatement, this.environment, this.labels,
|
|
||||||
this.exceptionComponents, this.expressionContinuation);
|
|
||||||
|
|
||||||
|
FinallyHandler(this.finallyStatement, this.environment, this.state);
|
||||||
Configuration call(Value exception, StackTrace stackTrace) {
|
Configuration call(Value exception, StackTrace stackTrace) {
|
||||||
// A finally handler can't handle an exception, only execute the
|
// A finally handler can't handle an exception, only execute the
|
||||||
// corresponding finally statement and rethrow.
|
// corresponding finally statement and rethrow.
|
||||||
var cont =
|
var cont =
|
||||||
new RethrowSK(exceptionComponents.handler, exception, stackTrace);
|
new RethrowSK(state.exceptionComponents.handler, exception, stackTrace);
|
||||||
var state =
|
var newState = state.withContinuation(cont);
|
||||||
new State(labels, exceptionComponents, expressionContinuation, cont);
|
return new ExecConfiguration(finallyStatement, environment, newState);
|
||||||
return new ExecConfiguration(finallyStatement, environment, state);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1364,7 +1409,7 @@ class FinallyHandler extends ExceptionHandler {
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
/// Represents the components for Exception handling.
|
/// 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.
|
/// components, current stacktrace and exception.
|
||||||
class ExceptionComponents {
|
class ExceptionComponents {
|
||||||
final ExceptionHandler handler;
|
final ExceptionHandler handler;
|
||||||
|
@ -1483,7 +1528,7 @@ class StatementExecuter
|
||||||
Configuration visitBreakStatement(
|
Configuration visitBreakStatement(
|
||||||
BreakStatement node, ExecConfiguration conf) {
|
BreakStatement node, ExecConfiguration conf) {
|
||||||
Label l = conf.state.lookupLabel(node.target);
|
Label l = conf.state.lookupLabel(node.target);
|
||||||
return new ForwardConfiguration(l.continuation, l.environment);
|
return new BreakConfiguration(l.continuation);
|
||||||
}
|
}
|
||||||
|
|
||||||
Configuration visitWhileStatement(
|
Configuration visitWhileStatement(
|
||||||
|
@ -1517,22 +1562,30 @@ class StatementExecuter
|
||||||
|
|
||||||
Configuration visitTryCatch(TryCatch node, ExecConfiguration conf) {
|
Configuration visitTryCatch(TryCatch node, ExecConfiguration conf) {
|
||||||
var handler = new CatchHandler(node.catches, conf.environment, conf.state);
|
var handler = new CatchHandler(node.catches, conf.environment, conf.state);
|
||||||
var handlers = new ExceptionComponents(
|
var exceptionComponents = new ExceptionComponents(
|
||||||
handler,
|
handler,
|
||||||
conf.state.exceptionComponents.stackTrace,
|
conf.state.exceptionComponents.stackTrace,
|
||||||
conf.state.exceptionComponents.currentStackTrace,
|
conf.state.exceptionComponents.currentStackTrace,
|
||||||
conf.state.exceptionComponents.currentException);
|
conf.state.exceptionComponents.currentException);
|
||||||
var state = conf.state.withException(handlers);
|
var state = conf.state.withException(exceptionComponents);
|
||||||
return new ExecConfiguration(node.body, conf.environment, state);
|
return new ExecConfiguration(node.body, conf.environment, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
Configuration visitTryFinally(TryFinally node, ExecConfiguration conf) {
|
Configuration visitTryFinally(TryFinally node, ExecConfiguration conf) {
|
||||||
// TODO(zhivkag): Add FinallyBreak to break labels.
|
|
||||||
var cont = new FinallySK(node.finalizer, conf.environment, conf.state);
|
var cont = new FinallySK(node.finalizer, conf.environment, conf.state);
|
||||||
var returnCont =
|
var returnCont =
|
||||||
new FinallyReturnEK(node.finalizer, conf.environment, conf.state);
|
new FinallyReturnEK(node.finalizer, conf.environment, conf.state);
|
||||||
return new ExecConfiguration(node.body, conf.environment,
|
var labels = conf.state.labels
|
||||||
conf.state.withContinuation(cont).withReturnContinuation(returnCont));
|
?.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(
|
Configuration visitVariableDeclaration(
|
||||||
|
|
18
pkg/kernel/testcases/interpreter/break_test.dart
Normal file
18
pkg/kernel/testcases/interpreter/break_test.dart
Normal file
|
@ -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++;
|
||||||
|
}
|
||||||
|
}
|
12
pkg/kernel/testcases/interpreter/break_test.dart.expect
Normal file
12
pkg/kernel/testcases/interpreter/break_test.dart.expect
Normal file
|
@ -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)
|
Loading…
Reference in a new issue