Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(49)

Unified Diff: pkg/kernel/lib/transformations/closure/rewriter.dart

Issue 2712473003: closure conversion: Support closures in initializers (Closed)
Patch Set: Address comments Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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;
+ }
+}
« no previous file with comments | « pkg/kernel/lib/transformations/closure/converter.dart ('k') | pkg/kernel/testcases/closures/closure_in_constructor.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698