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); |
+ } |
+} |