| Index: pkg/kernel/lib/transformations/closure/context.dart
|
| diff --git a/pkg/kernel/lib/transformations/closure/context.dart b/pkg/kernel/lib/transformations/closure/context.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..3a3495e1aea04876b9755b211af885b076eb25c7
|
| --- /dev/null
|
| +++ b/pkg/kernel/lib/transformations/closure/context.dart
|
| @@ -0,0 +1,248 @@
|
| +// Copyright (c) 2016, 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.
|
| +
|
| +library kernel.transformations.closure.context;
|
| +
|
| +import '../../ast.dart'
|
| + show
|
| + Arguments,
|
| + Class,
|
| + ConstructorInvocation,
|
| + Expression,
|
| + ExpressionStatement,
|
| + IntLiteral,
|
| + InterfaceType,
|
| + MethodInvocation,
|
| + Name,
|
| + NullLiteral,
|
| + PropertyGet,
|
| + PropertySet,
|
| + StringLiteral,
|
| + Throw,
|
| + VariableDeclaration,
|
| + VariableGet,
|
| + VariableSet;
|
| +
|
| +import '../../frontend/accessors.dart'
|
| + show Accessor, IndexAccessor, VariableAccessor;
|
| +
|
| +import 'converter.dart' show ClosureConverter;
|
| +
|
| +abstract class Context {
|
| + /// Returns a new expression for accessing this context.
|
| + Expression get expression;
|
| +
|
| + /// Returns an accessor (or null) for accessing this context.
|
| + Accessor get accessor;
|
| +
|
| + /// Extend the context to include [variable] initialized to [value]. For
|
| + /// example, this replaces the [VariableDeclaration] node of a captured local
|
| + /// variable.
|
| + ///
|
| + /// This may create a new context and update the `context` field of the
|
| + /// current [ClosureConverter].
|
| + // TODO(ahe): Return context instead?
|
| + void extend(VariableDeclaration variable, Expression value);
|
| +
|
| + /// Update the initializer [value] of [variable] which was previously added
|
| + /// with [extend]. This is used when [value] isn't available when the context
|
| + /// was extended.
|
| + void update(VariableDeclaration variable, Expression value) {
|
| + throw "not supported $runtimeType";
|
| + }
|
| +
|
| + /// Returns a new expression for reading the value of [variable] from this
|
| + /// context. For example, for replacing a [VariableGet] of a captured local
|
| + /// variable.
|
| + Expression lookup(VariableDeclaration variable);
|
| +
|
| + /// Returns a new expression which stores [value] in [variable] in this
|
| + /// context. For example, for replacing a [VariableSet] of a captured local
|
| + /// variable.
|
| + Expression assign(VariableDeclaration variable, Expression value,
|
| + {bool voidContext: false});
|
| +
|
| + /// Returns a new context whose parent is this context. The optional argument
|
| + /// [accessor] controls how the nested context access this context. This is
|
| + /// used, for example, when hoisting a local function. In this case, access
|
| + /// to this context can't be accessed directly via [expression]. In other
|
| + /// cases, for example, a for-loop, this context is still in scope and can be
|
| + /// accessed directly (with [accessor]).
|
| + Context toNestedContext([Accessor accessor]);
|
| +
|
| + /// Returns a new expression which will copy this context and store the copy
|
| + /// in the local variable currently holding this context.
|
| + Expression clone() {
|
| + return new Throw(
|
| + new StringLiteral("Context clone not implemented for ${runtimeType}"));
|
| + }
|
| +}
|
| +
|
| +class NoContext extends Context {
|
| + final ClosureConverter converter;
|
| +
|
| + NoContext(this.converter);
|
| +
|
| + Expression get expression => new NullLiteral();
|
| +
|
| + Accessor get accessor => null;
|
| +
|
| + void extend(VariableDeclaration variable, Expression value) {
|
| + converter.context = new LocalContext(converter, this)
|
| + ..extend(variable, value);
|
| + }
|
| +
|
| + Expression lookup(VariableDeclaration variable) {
|
| + throw 'Unbound NoContext.lookup($variable)';
|
| + }
|
| +
|
| + Expression assign(VariableDeclaration variable, Expression value,
|
| + {bool voidContext: false}) {
|
| + throw 'Unbound NoContext.assign($variable, ...)';
|
| + }
|
| +
|
| + Context toNestedContext([Accessor accessor]) {
|
| + return new NestedContext(
|
| + converter, accessor, <List<VariableDeclaration>>[]);
|
| + }
|
| +}
|
| +
|
| +class LocalContext extends Context {
|
| + final ClosureConverter converter;
|
| + final Context parent;
|
| + final VariableDeclaration self;
|
| + final IntLiteral size;
|
| + final List<VariableDeclaration> variables = <VariableDeclaration>[];
|
| + final Map<VariableDeclaration, Arguments> initializers =
|
| + <VariableDeclaration, Arguments>{};
|
| +
|
| + LocalContext._internal(this.converter, this.parent, this.self, this.size);
|
| +
|
| + factory LocalContext(ClosureConverter converter, Context parent) {
|
| + Class contextClass = converter.contextClass;
|
| + assert(contextClass.constructors.length == 1);
|
| + IntLiteral zero = new IntLiteral(0);
|
| + VariableDeclaration declaration = new VariableDeclaration.forValue(
|
| + new ConstructorInvocation(
|
| + contextClass.constructors.first, new Arguments(<Expression>[zero])),
|
| + type: new InterfaceType(contextClass));
|
| + declaration.name = "#context";
|
| + converter.insert(declaration);
|
| + converter.insert(new ExpressionStatement(new PropertySet(
|
| + new VariableGet(declaration), new Name('parent'), parent.expression)));
|
| +
|
| + return new LocalContext._internal(converter, parent, declaration, zero);
|
| + }
|
| +
|
| + Expression get expression => accessor.buildSimpleRead();
|
| +
|
| + Accessor get accessor => new VariableAccessor(self);
|
| +
|
| + void extend(VariableDeclaration variable, Expression value) {
|
| + Arguments arguments =
|
| + new Arguments(<Expression>[new IntLiteral(variables.length), value]);
|
| + converter.insert(new ExpressionStatement(
|
| + new MethodInvocation(expression, new Name('[]='), arguments)));
|
| + ++size.value;
|
| + variables.add(variable);
|
| + initializers[variable] = arguments;
|
| + }
|
| +
|
| + void update(VariableDeclaration variable, Expression value) {
|
| + Arguments arguments = initializers[variable];
|
| + arguments.positional[1] = value;
|
| + value.parent = arguments;
|
| + }
|
| +
|
| + Expression lookup(VariableDeclaration variable) {
|
| + var index = variables.indexOf(variable);
|
| + return index == -1
|
| + ? parent.lookup(variable)
|
| + : new MethodInvocation(expression, new Name('[]'),
|
| + new Arguments(<Expression>[new IntLiteral(index)]));
|
| + }
|
| +
|
| + Expression assign(VariableDeclaration variable, Expression value,
|
| + {bool voidContext: false}) {
|
| + var index = variables.indexOf(variable);
|
| + return index == -1
|
| + ? parent.assign(variable, value, voidContext: voidContext)
|
| + : IndexAccessor
|
| + .make(expression, new IntLiteral(index), null, null)
|
| + .buildAssignment(value, voidContext: voidContext);
|
| + }
|
| +
|
| + Context toNestedContext([Accessor accessor]) {
|
| + accessor ??= this.accessor;
|
| + List<List<VariableDeclaration>> variabless = <List<VariableDeclaration>>[];
|
| + var current = this;
|
| + while (current != null && current is! NoContext) {
|
| + if (current is LocalContext) {
|
| + variabless.add(current.variables);
|
| + current = current.parent;
|
| + } else if (current is NestedContext) {
|
| + variabless.addAll((current as NestedContext).variabless);
|
| + current = null;
|
| + }
|
| + }
|
| + return new NestedContext(converter, accessor, variabless);
|
| + }
|
| +
|
| + Expression clone() {
|
| + self.isFinal = false;
|
| + return new VariableSet(
|
| + self,
|
| + new MethodInvocation(
|
| + new VariableGet(self), new Name("copy"), new Arguments.empty()));
|
| + }
|
| +}
|
| +
|
| +class NestedContext extends Context {
|
| + final ClosureConverter converter;
|
| + final Accessor accessor;
|
| + final List<List<VariableDeclaration>> variabless;
|
| +
|
| + NestedContext(this.converter, this.accessor, this.variabless);
|
| +
|
| + Expression get expression {
|
| + return accessor?.buildSimpleRead() ?? new NullLiteral();
|
| + }
|
| +
|
| + void extend(VariableDeclaration variable, Expression value) {
|
| + converter.context = new LocalContext(converter, this)
|
| + ..extend(variable, value);
|
| + }
|
| +
|
| + Expression lookup(VariableDeclaration variable) {
|
| + var context = expression;
|
| + for (var variables in variabless) {
|
| + var index = variables.indexOf(variable);
|
| + if (index != -1) {
|
| + return new MethodInvocation(context, new Name('[]'),
|
| + new Arguments(<Expression>[new IntLiteral(index)]));
|
| + }
|
| + context = new PropertyGet(context, new Name('parent'));
|
| + }
|
| + throw 'Unbound NestedContext.lookup($variable)';
|
| + }
|
| +
|
| + Expression assign(VariableDeclaration variable, Expression value,
|
| + {bool voidContext: false}) {
|
| + var context = expression;
|
| + for (var variables in variabless) {
|
| + var index = variables.indexOf(variable);
|
| + if (index != -1) {
|
| + return IndexAccessor
|
| + .make(context, new IntLiteral(index), null, null)
|
| + .buildAssignment(value, voidContext: voidContext);
|
| + }
|
| + context = new PropertyGet(context, new Name('parent'));
|
| + }
|
| + throw 'Unbound NestedContext.lookup($variable)';
|
| + }
|
| +
|
| + Context toNestedContext([Accessor accessor]) {
|
| + return new NestedContext(converter, accessor ?? this.accessor, variabless);
|
| + }
|
| +}
|
|
|