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