Index: pkg/kernel/lib/transformations/closure_conversion.dart |
diff --git a/pkg/kernel/lib/transformations/closure_conversion.dart b/pkg/kernel/lib/transformations/closure_conversion.dart |
deleted file mode 100644 |
index 18da0669c04c89545b677b9cf90cdf573bcdf5cd..0000000000000000000000000000000000000000 |
--- a/pkg/kernel/lib/transformations/closure_conversion.dart |
+++ /dev/null |
@@ -1,440 +0,0 @@ |
-// 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_conversion; |
- |
-import '../ast.dart'; |
-import '../core_types.dart'; |
-import '../visitor.dart'; |
- |
-Program transformProgram(Program program) { |
- var captured = new CapturedVariables(); |
- captured.visitProgram(program); |
- |
- var convert = |
- new ClosureConverter(new CoreTypes(program), captured.variables); |
- return convert.visitProgram(program); |
-} |
- |
-class CapturedVariables extends RecursiveVisitor { |
- FunctionNode _currentFunction; |
- final Map<VariableDeclaration, FunctionNode> _function = |
- <VariableDeclaration, FunctionNode>{}; |
- |
- final Set<VariableDeclaration> variables = new Set<VariableDeclaration>(); |
- |
- visitFunctionNode(FunctionNode node) { |
- var saved = _currentFunction; |
- _currentFunction = node; |
- node.visitChildren(this); |
- _currentFunction = saved; |
- } |
- |
- visitVariableDeclaration(VariableDeclaration node) { |
- _function[node] = _currentFunction; |
- node.visitChildren(this); |
- } |
- |
- visitVariableGet(VariableGet node) { |
- if (_function[node.variable] != _currentFunction) { |
- variables.add(node.variable); |
- } |
- node.visitChildren(this); |
- } |
- |
- visitVariableSet(VariableSet node) { |
- if (_function[node.variable] != _currentFunction) { |
- variables.add(node.variable); |
- } |
- node.visitChildren(this); |
- } |
-} |
- |
-abstract class Context { |
- Expression get expression; |
- |
- void extend(VariableDeclaration variable, Expression value); |
- |
- Expression lookup(VariableDeclaration variable); |
- Expression assign(VariableDeclaration variable, Expression value); |
- |
- Context toClosureContext(VariableDeclaration parameter); |
-} |
- |
-class NoContext extends Context { |
- final ClosureConverter converter; |
- |
- NoContext(this.converter); |
- |
- Expression get expression => new NullLiteral(); |
- |
- 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) { |
- throw 'Unbound NoContext.assign($variable, ...)'; |
- } |
- |
- Context toClosureContext(VariableDeclaration parameter) { |
- return new ClosureContext(converter, parameter, |
- <List<VariableDeclaration>>[]); |
- } |
-} |
- |
- |
-class LocalContext extends Context { |
- final ClosureConverter converter; |
- final Context parent; |
- final VariableDeclaration self; |
- final IntLiteral size; |
- final List<VariableDeclaration> variables = <VariableDeclaration>[]; |
- |
- LocalContext._internal(this.converter, this.parent, this.self, this.size); |
- |
- factory LocalContext(ClosureConverter converter, Context parent) { |
- Class contextClass = converter.internalContextClass; |
- 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)); |
- 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 => new VariableGet(self); |
- |
- void extend(VariableDeclaration variable, Expression value) { |
- converter.insert( |
- new ExpressionStatement( |
- new MethodInvocation( |
- expression, |
- new Name('[]='), |
- new Arguments( |
- <Expression>[new IntLiteral(variables.length), value])))); |
- ++size.value; |
- variables.add(variable); |
- } |
- |
- 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) { |
- var index = variables.indexOf(variable); |
- return index == -1 |
- ? parent.assign(variable, value) |
- : new MethodInvocation( |
- expression, |
- new Name('[]='), |
- new Arguments(<Expression>[new IntLiteral(index), value])); |
- } |
- |
- Context toClosureContext(VariableDeclaration parameter) { |
- 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 ClosureContext) { |
- variabless.addAll(current.variabless); |
- current = null; |
- } else if (current is LoopContext) { |
- // TODO. |
- current = current.parent; |
- } |
- } |
- return new ClosureContext(converter, parameter, variabless); |
- } |
-} |
- |
-class LoopContext { |
- final ClosureConverter converter; |
- final Context parent; |
- |
- LoopContext(this.converter, this.parent); |
- |
- void extend(VariableDeclaration variable, Expression value) { |
- converter.context = |
- new LocalContext(converter, parent)..extend(variable, value); |
- } |
-} |
- |
-class ClosureContext extends Context { |
- final ClosureConverter converter; |
- final VariableDeclaration self; |
- final List<List<VariableDeclaration>> variabless; |
- |
- ClosureContext(this.converter, this.self, this.variabless); |
- |
- Expression get expression => new VariableGet(self); |
- |
- 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 ClosureContext.lookup($variable)'; |
- } |
- |
- Expression assign(VariableDeclaration variable, Expression value) { |
- 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), value])); |
- } |
- context = new PropertyGet(context, new Name('parent')); |
- } |
- throw 'Unbound ClosureContext.lookup($variable)'; |
- } |
- |
- Context toClosureContext(VariableDeclaration parameter) { |
- return new ClosureContext(converter, parameter, variabless); |
- } |
-} |
- |
-class ClosureConverter extends Transformer { |
- final CoreTypes coreTypes; |
- Class internalContextClass; |
- final Set<VariableDeclaration> captured; |
- |
- Block _currentBlock; |
- int _insertionIndex = 0; |
- |
- Context context; |
- |
- ClosureConverter(this.coreTypes, this.captured) { |
- internalContextClass = coreTypes.getCoreClass('dart:_internal', 'Context'); |
- } |
- |
- void insert(Statement statement) { |
- _currentBlock.statements.insert(_insertionIndex++, statement); |
- statement.parent = _currentBlock; |
- } |
- |
- TreeNode visitConstructor(Constructor node) { |
- return node; |
- } |
- |
- TreeNode visitFunctionDeclaration(FunctionDeclaration node) { |
- if (captured.contains(node.variable)) { |
- context.extend(node.variable, |
- new FunctionExpression(node.function)); |
- } |
- |
- Block savedBlock = _currentBlock; |
- int savedIndex = _insertionIndex; |
- Context savedContext = context; |
- |
- Statement body = node.function.body; |
- assert(body != null); |
- |
- if (body is Block) { |
- _currentBlock = body; |
- } else { |
- _currentBlock = new Block(<Statement>[body]); |
- node.function.body = body.parent = _currentBlock; |
- } |
- _insertionIndex = 0; |
- |
- // TODO: This is really the closure, not the context. |
- VariableDeclaration parameter = |
- new VariableDeclaration(null, |
- type: internalContextClass.rawType, |
- isFinal: true); |
- node.function.positionalParameters.insert(0, parameter); |
- parameter.parent = node.function; |
- ++node.function.requiredParameterCount; |
- context = context.toClosureContext(parameter); |
- |
- // Don't visit the children, because that included a variable declaration. |
- node.function = node.function.accept(this); |
- |
- _currentBlock = savedBlock; |
- _insertionIndex = savedIndex; |
- context = savedContext; |
- |
- return captured.contains(node.variable) ? null : node; |
- } |
- |
- TreeNode visitFunctionExpression(FunctionExpression node) { |
- Block savedBlock = _currentBlock; |
- int savedIndex = _insertionIndex; |
- Context savedContext = context; |
- |
- Statement body = node.function.body; |
- assert(body != null); |
- |
- if (body is Block) { |
- _currentBlock = body; |
- } else { |
- _currentBlock = new Block(<Statement>[body]); |
- node.function.body = body.parent = _currentBlock; |
- } |
- _insertionIndex = 0; |
- |
- // TODO: This is really the closure, not the context. |
- VariableDeclaration parameter = |
- new VariableDeclaration(null, |
- type: internalContextClass.rawType, |
- isFinal: true); |
- node.function.positionalParameters.insert(0, parameter); |
- parameter.parent = node.function; |
- ++node.function.requiredParameterCount; |
- context = context.toClosureContext(parameter); |
- |
- node.transformChildren(this); |
- |
- _currentBlock = savedBlock; |
- _insertionIndex = savedIndex; |
- context = savedContext; |
- |
- return node; |
- } |
- |
- TreeNode visitProcedure(Procedure node) { |
- assert(_currentBlock == null); |
- assert(_insertionIndex == 0); |
- assert(context == null); |
- |
- Statement body = node.function.body; |
- if (body == null) return node; |
- |
- // Ensure that the body is a block which becomes the current block. |
- if (body is Block) { |
- _currentBlock = body; |
- } else { |
- _currentBlock = new Block(<Statement>[body]); |
- node.function.body = body.parent = _currentBlock; |
- } |
- _insertionIndex = 0; |
- |
- // Start with no context. This happens after setting up _currentBlock |
- // so statements can be emitted into _currentBlock if necessary. |
- context = new NoContext(this); |
- |
- node.transformChildren(this); |
- |
- _currentBlock = null; |
- _insertionIndex = 0; |
- context = null; |
- return node; |
- } |
- |
- TreeNode visitLocalInitializer(LocalInitializer node) { |
- assert(!captured.contains(node.variable)); |
- node.transformChildren(this); |
- return node; |
- } |
- |
- TreeNode visitFunctionNode(FunctionNode node) { |
- transformList(node.typeParameters, this, node); |
- |
- void extend(VariableDeclaration parameter) { |
- context.extend(parameter, new VariableGet(parameter)); |
- } |
- // TODO: Can parameters contain initializers (e.g., for optional ones) that |
- // need to be closure converted? |
- node.positionalParameters.where(captured.contains).forEach(extend); |
- node.namedParameters.where(captured.contains).forEach(extend); |
- |
- assert(node.body != null); |
- node.body = node.body.accept(this); |
- node.body.parent = node; |
- return node; |
- } |
- |
- TreeNode visitBlock(Block node) { |
- Block savedBlock; |
- int savedIndex; |
- if (_currentBlock != node) { |
- savedBlock = _currentBlock; |
- savedIndex = _insertionIndex; |
- _currentBlock = node; |
- _insertionIndex = 0; |
- } |
- |
- while (_insertionIndex < _currentBlock.statements.length) { |
- assert(_currentBlock == node); |
- |
- var original = _currentBlock.statements[_insertionIndex]; |
- var transformed = original.accept(this); |
- assert(_currentBlock.statements[_insertionIndex] == original); |
- if (transformed == null) { |
- _currentBlock.statements.removeAt(_insertionIndex); |
- } else { |
- _currentBlock.statements[_insertionIndex++] = transformed; |
- transformed.parent = _currentBlock; |
- } |
- } |
- |
- if (savedBlock != null) { |
- _currentBlock = savedBlock; |
- _insertionIndex = savedIndex; |
- } |
- return node; |
- } |
- |
- TreeNode visitVariableDeclaration(VariableDeclaration node) { |
- node.transformChildren(this); |
- |
- if (!captured.contains(node)) return node; |
- context.extend(node, node.initializer ?? new NullLiteral()); |
- |
- // TODO(ahe): Return null here when the parent has been correctly |
- // rewritten. So far, only for-in is known to use this return value. |
- return new VariableDeclaration(null, initializer: new InvalidExpression()); |
- } |
- |
- TreeNode visitVariableGet(VariableGet node) { |
- return captured.contains(node.variable) |
- ? context.lookup(node.variable) |
- : node; |
- } |
- |
- TreeNode visitVariableSet(VariableSet node) { |
- node.transformChildren(this); |
- |
- return captured.contains(node.variable) |
- ? context.assign(node.variable, node.value) |
- : node; |
- } |
-} |