mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 16:41:07 +00:00
Remove closure_conversion.dart from pkg/kernel.
This file is not strong-mode clean, but since a more recent version of closure conversion still exists in a branch on the kernel github repo, there is not much point in fixing this version of it. BUG= R=ahe@google.com Review URL: https://codereview.chromium.org/2526793002 .
This commit is contained in:
parent
f13881ac08
commit
5d310431bd
|
@ -12,7 +12,6 @@ import 'package:kernel/checks.dart' as checks;
|
|||
import 'package:kernel/transformations/continuation.dart' as cont;
|
||||
import 'package:kernel/transformations/infer_values.dart' as infer_values;
|
||||
import 'package:kernel/transformations/mixin_full_resolution.dart' as mix;
|
||||
import 'package:kernel/transformations/closure_conversion.dart' as closures;
|
||||
import 'package:kernel/transformations/treeshaker.dart' as treeshaker;
|
||||
|
||||
import 'batch_util.dart';
|
||||
|
@ -23,10 +22,7 @@ ArgParser parser = new ArgParser()
|
|||
allowed: ['text', 'bin'],
|
||||
defaultsTo: 'bin',
|
||||
help: 'Output format.')
|
||||
..addOption('out',
|
||||
abbr: 'o',
|
||||
help: 'Output file.',
|
||||
defaultsTo: null)
|
||||
..addOption('out', abbr: 'o', help: 'Output file.', defaultsTo: null)
|
||||
..addFlag('verbose',
|
||||
abbr: 'v',
|
||||
negatable: false,
|
||||
|
@ -76,13 +72,11 @@ Future<CompilerOutcome> runTransformation(List<String> arguments) async {
|
|||
case 'resolve-mixins':
|
||||
program = mix.transformProgram(program);
|
||||
break;
|
||||
case 'closures':
|
||||
program = closures.transformProgram(program);
|
||||
break;
|
||||
case 'treeshake':
|
||||
program = treeshaker.transformProgram(program);
|
||||
break;
|
||||
default: throw 'Unknown transformation';
|
||||
default:
|
||||
throw 'Unknown transformation';
|
||||
}
|
||||
|
||||
program.accept(new checks.CheckParentPointers());
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue