| Index: pkg/kernel/lib/transformations/closure/rewriter.dart
|
| diff --git a/pkg/kernel/lib/transformations/closure/rewriter.dart b/pkg/kernel/lib/transformations/closure/rewriter.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..88b921ce194e429bb78a38e325a2008d68c256af
|
| --- /dev/null
|
| +++ b/pkg/kernel/lib/transformations/closure/rewriter.dart
|
| @@ -0,0 +1,125 @@
|
| +// Copyright (c) 2017, 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.rewriter;
|
| +
|
| +import '../../ast.dart';
|
| +import 'converter.dart' show ClosureConverter;
|
| +
|
| +/// Used by the [Context] to initialize and update the context variable
|
| +/// used to capture the variables closed over by functions.
|
| +abstract class AstRewriter {
|
| + /// The declared variable that holds the context.
|
| + VariableDeclaration contextDeclaration;
|
| +
|
| + /// The expression used to initialize the size of the context stored in
|
| + /// [contextDeclaration]. This expression is modified when the context is
|
| + /// extended.
|
| + IntLiteral contextSize;
|
| +
|
| + /// Creates a new [AstRewriter] for a (nested) [Block].
|
| + BlockRewriter forNestedBlock(Block block);
|
| +
|
| + /// Inserts an allocation of a context and initializes [contextDeclaration]
|
| + /// and [contextSize].
|
| + void insertContextDeclaration(Class contextClass, Expression accessParent);
|
| +
|
| + /// Inserts an expression or statement that extends the context, where
|
| + /// [arguments] holds a pair of the new index and the initial value.
|
| + void insertExtendContext(Expression accessContext, Arguments arguments);
|
| +
|
| + void _createDeclaration(Class contextClass) {
|
| + assert(contextDeclaration == null && contextSize == null);
|
| +
|
| + contextSize = new IntLiteral(0);
|
| + contextDeclaration = new VariableDeclaration.forValue(
|
| + new ConstructorInvocation(contextClass.constructors.first,
|
| + new Arguments(<Expression>[contextSize])),
|
| + type: new InterfaceType(contextClass));
|
| + contextDeclaration.name = "#context";
|
| + }
|
| +}
|
| +
|
| +/// Adds a local variable for the context and adds update [Statement]s to the
|
| +/// current block.
|
| +class BlockRewriter extends AstRewriter {
|
| + Block _currentBlock;
|
| + int _insertionIndex;
|
| +
|
| + BlockRewriter(this._currentBlock) : _insertionIndex = 0;
|
| +
|
| + BlockRewriter forNestedBlock(Block block) {
|
| + return _currentBlock != block ? new BlockRewriter(block) : this;
|
| + }
|
| +
|
| + void transformStatements(Block block, ClosureConverter converter) {
|
| + while (_insertionIndex < _currentBlock.statements.length) {
|
| + var original = _currentBlock.statements[_insertionIndex];
|
| + var transformed = original.accept(converter);
|
| + assert(_currentBlock.statements[_insertionIndex] == original);
|
| + if (transformed == null) {
|
| + _currentBlock.statements.removeAt(_insertionIndex);
|
| + } else {
|
| + _currentBlock.statements[_insertionIndex++] = transformed;
|
| + transformed.parent = _currentBlock;
|
| + }
|
| + }
|
| + }
|
| +
|
| + void _insertStatement(Statement statement) {
|
| + _currentBlock.statements.insert(_insertionIndex++, statement);
|
| + statement.parent = _currentBlock;
|
| + }
|
| +
|
| + void insertContextDeclaration(Class contextClass, Expression accessParent) {
|
| + _createDeclaration(contextClass);
|
| + _insertStatement(contextDeclaration);
|
| + _insertStatement(new ExpressionStatement(new PropertySet(
|
| + new VariableGet(contextDeclaration),
|
| + new Name('parent'),
|
| + accessParent)));
|
| + }
|
| +
|
| + void insertExtendContext(Expression accessContext, Arguments arguments) {
|
| + _insertStatement(new ExpressionStatement(
|
| + new MethodInvocation(accessContext, new Name('[]='), arguments)));
|
| + }
|
| +}
|
| +
|
| +/// Creates and updates the context as [Let] bindings around the initializer
|
| +/// expression.
|
| +class InitializerRewriter extends AstRewriter {
|
| + final Expression initializingExpression;
|
| +
|
| + InitializerRewriter(this.initializingExpression) {
|
| + assert(initializingExpression.parent is FieldInitializer);
|
| + }
|
| +
|
| + @override
|
| + BlockRewriter forNestedBlock(Block block) {
|
| + return new BlockRewriter(block);
|
| + }
|
| +
|
| + @override
|
| + void insertContextDeclaration(Class contextClass, Expression accessParent) {
|
| + _createDeclaration(contextClass);
|
| + FieldInitializer parent = initializingExpression.parent;
|
| + Let binding = new Let(contextDeclaration, initializingExpression);
|
| + initializingExpression.parent = binding;
|
| + parent.value = binding;
|
| + binding.parent = parent;
|
| + }
|
| +
|
| + @override
|
| + void insertExtendContext(Expression accessContext, Arguments arguments) {
|
| + Expression extendContext =
|
| + new MethodInvocation(accessContext, new Name('[]='), arguments);
|
| + Let parent = initializingExpression.parent;
|
| + Let binding = new Let(
|
| + new VariableDeclaration(null, initializer: extendContext),
|
| + initializingExpression);
|
| + parent.body = binding;
|
| + binding.parent = parent;
|
| + }
|
| +}
|
|
|