OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 library kernel.transformations.closure.context; |
| 6 |
| 7 import '../../ast.dart' show |
| 8 Arguments, |
| 9 Class, |
| 10 ConstructorInvocation, |
| 11 Expression, |
| 12 ExpressionStatement, |
| 13 IntLiteral, |
| 14 InterfaceType, |
| 15 MethodInvocation, |
| 16 Name, |
| 17 NullLiteral, |
| 18 PropertyGet, |
| 19 PropertySet, |
| 20 StringLiteral, |
| 21 Throw, |
| 22 VariableDeclaration, |
| 23 VariableGet, |
| 24 VariableSet; |
| 25 |
| 26 import '../../frontend/accessors.dart' show |
| 27 Accessor, |
| 28 IndexAccessor, |
| 29 VariableAccessor; |
| 30 |
| 31 import 'converter.dart' show |
| 32 ClosureConverter; |
| 33 |
| 34 abstract class Context { |
| 35 /// Returns a new expression for accessing this context. |
| 36 Expression get expression; |
| 37 |
| 38 /// Returns an accessor (or null) for accessing this context. |
| 39 Accessor get accessor; |
| 40 |
| 41 /// Extend the context to include [variable] initialized to [value]. For |
| 42 /// example, this replaces the [VariableDeclaration] node of a captured local |
| 43 /// variable. |
| 44 /// |
| 45 /// This may create a new context and update the `context` field of the |
| 46 /// current [ClosureConverter]. |
| 47 // TODO(ahe): Return context instead? |
| 48 void extend(VariableDeclaration variable, Expression value); |
| 49 |
| 50 /// Update the initializer [value] of [variable] which was previously added |
| 51 /// with [extend]. This is used when [value] isn't available when the context |
| 52 /// was extended. |
| 53 void update(VariableDeclaration variable, Expression value) { |
| 54 throw "not supported $runtimeType"; |
| 55 } |
| 56 |
| 57 /// Returns a new expression for reading the value of [variable] from this |
| 58 /// context. For example, for replacing a [VariableGet] of a captured local |
| 59 /// variable. |
| 60 Expression lookup(VariableDeclaration variable); |
| 61 |
| 62 /// Returns a new expression which stores [value] in [variable] in this |
| 63 /// context. For example, for replacing a [VariableSet] of a captured local |
| 64 /// variable. |
| 65 Expression assign(VariableDeclaration variable, Expression value, |
| 66 {bool voidContext: false}); |
| 67 |
| 68 /// Returns a new context whose parent is this context. The optional argument |
| 69 /// [accessor] controls how the nested context access this context. This is |
| 70 /// used, for example, when hoisting a local function. In this case, access |
| 71 /// to this context can't be accessed directly via [expression]. In other |
| 72 /// cases, for example, a for-loop, this context is still in scope and can be |
| 73 /// accessed directly (with [accessor]). |
| 74 Context toNestedContext([Accessor accessor]); |
| 75 |
| 76 /// Returns a new expression which will copy this context and store the copy |
| 77 /// in the local variable currently holding this context. |
| 78 Expression clone() { |
| 79 return new Throw( |
| 80 new StringLiteral( |
| 81 "Context clone not implemented for ${runtimeType}")); |
| 82 } |
| 83 } |
| 84 |
| 85 class NoContext extends Context { |
| 86 final ClosureConverter converter; |
| 87 |
| 88 NoContext(this.converter); |
| 89 |
| 90 Expression get expression => new NullLiteral(); |
| 91 |
| 92 Accessor get accessor => null; |
| 93 |
| 94 void extend(VariableDeclaration variable, Expression value) { |
| 95 converter.context = |
| 96 new LocalContext(converter, this)..extend(variable, value); |
| 97 } |
| 98 |
| 99 Expression lookup(VariableDeclaration variable) { |
| 100 throw 'Unbound NoContext.lookup($variable)'; |
| 101 } |
| 102 |
| 103 Expression assign(VariableDeclaration variable, Expression value, |
| 104 {bool voidContext: false}) { |
| 105 throw 'Unbound NoContext.assign($variable, ...)'; |
| 106 } |
| 107 |
| 108 Context toNestedContext([Accessor accessor]) { |
| 109 return new NestedContext(converter, accessor, |
| 110 <List<VariableDeclaration>>[]); |
| 111 } |
| 112 } |
| 113 |
| 114 class LocalContext extends Context { |
| 115 final ClosureConverter converter; |
| 116 final Context parent; |
| 117 final VariableDeclaration self; |
| 118 final IntLiteral size; |
| 119 final List<VariableDeclaration> variables = <VariableDeclaration>[]; |
| 120 final Map<VariableDeclaration, Arguments> initializers = |
| 121 <VariableDeclaration, Arguments>{}; |
| 122 |
| 123 LocalContext._internal(this.converter, this.parent, this.self, this.size); |
| 124 |
| 125 factory LocalContext(ClosureConverter converter, Context parent) { |
| 126 Class contextClass = converter.contextClass; |
| 127 assert(contextClass.constructors.length == 1); |
| 128 IntLiteral zero = new IntLiteral(0); |
| 129 VariableDeclaration declaration = |
| 130 new VariableDeclaration.forValue( |
| 131 new ConstructorInvocation(contextClass.constructors.first, |
| 132 new Arguments(<Expression>[zero])), |
| 133 type: new InterfaceType(contextClass)); |
| 134 declaration.name = "#context"; |
| 135 converter.insert(declaration); |
| 136 converter.insert(new ExpressionStatement( |
| 137 new PropertySet(new VariableGet(declaration), |
| 138 new Name('parent'), |
| 139 parent.expression))); |
| 140 |
| 141 return new LocalContext._internal(converter, parent, declaration, zero); |
| 142 } |
| 143 |
| 144 Expression get expression => accessor.buildSimpleRead(); |
| 145 |
| 146 Accessor get accessor => new VariableAccessor(self); |
| 147 |
| 148 void extend(VariableDeclaration variable, Expression value) { |
| 149 Arguments arguments = new Arguments( |
| 150 <Expression>[new IntLiteral(variables.length), value]); |
| 151 converter.insert( |
| 152 new ExpressionStatement( |
| 153 new MethodInvocation(expression, new Name('[]='), arguments))); |
| 154 ++size.value; |
| 155 variables.add(variable); |
| 156 initializers[variable] = arguments; |
| 157 } |
| 158 |
| 159 void update(VariableDeclaration variable, Expression value) { |
| 160 Arguments arguments = initializers[variable]; |
| 161 arguments.positional[1] = value; |
| 162 value.parent = arguments; |
| 163 } |
| 164 |
| 165 Expression lookup(VariableDeclaration variable) { |
| 166 var index = variables.indexOf(variable); |
| 167 return index == -1 |
| 168 ? parent.lookup(variable) |
| 169 : new MethodInvocation( |
| 170 expression, |
| 171 new Name('[]'), |
| 172 new Arguments(<Expression>[new IntLiteral(index)])); |
| 173 } |
| 174 |
| 175 Expression assign(VariableDeclaration variable, Expression value, |
| 176 {bool voidContext: false}) { |
| 177 var index = variables.indexOf(variable); |
| 178 return index == -1 |
| 179 ? parent.assign(variable, value, voidContext: voidContext) |
| 180 : IndexAccessor.make(expression, new IntLiteral(index), null, null) |
| 181 .buildAssignment(value, voidContext: voidContext); |
| 182 } |
| 183 |
| 184 Context toNestedContext([Accessor accessor]) { |
| 185 accessor ??= this.accessor; |
| 186 List<List<VariableDeclaration>> variabless = <List<VariableDeclaration>>[]; |
| 187 var current = this; |
| 188 while (current != null && current is! NoContext) { |
| 189 if (current is LocalContext) { |
| 190 variabless.add(current.variables); |
| 191 current = current.parent; |
| 192 } else if (current is NestedContext) { |
| 193 variabless.addAll(current.variabless); |
| 194 current = null; |
| 195 } |
| 196 } |
| 197 return new NestedContext(converter, accessor, variabless); |
| 198 } |
| 199 |
| 200 Expression clone() { |
| 201 self.isFinal = false; |
| 202 return new VariableSet( |
| 203 self, new MethodInvocation( |
| 204 new VariableGet(self), new Name("copy"), new Arguments.empty())); |
| 205 } |
| 206 } |
| 207 |
| 208 class NestedContext extends Context { |
| 209 final ClosureConverter converter; |
| 210 final Accessor accessor; |
| 211 final List<List<VariableDeclaration>> variabless; |
| 212 |
| 213 NestedContext(this.converter, this.accessor, this.variabless); |
| 214 |
| 215 Expression get expression { |
| 216 return accessor?.buildSimpleRead() ?? new NullLiteral(); |
| 217 } |
| 218 |
| 219 void extend(VariableDeclaration variable, Expression value) { |
| 220 converter.context = |
| 221 new LocalContext(converter, this)..extend(variable, value); |
| 222 } |
| 223 |
| 224 Expression lookup(VariableDeclaration variable) { |
| 225 var context = expression; |
| 226 for (var variables in variabless) { |
| 227 var index = variables.indexOf(variable); |
| 228 if (index != -1) { |
| 229 return new MethodInvocation( |
| 230 context, |
| 231 new Name('[]'), |
| 232 new Arguments(<Expression>[new IntLiteral(index)])); |
| 233 } |
| 234 context = new PropertyGet(context, new Name('parent')); |
| 235 } |
| 236 throw 'Unbound NestedContext.lookup($variable)'; |
| 237 } |
| 238 |
| 239 Expression assign(VariableDeclaration variable, Expression value, |
| 240 {bool voidContext: false}) { |
| 241 var context = expression; |
| 242 for (var variables in variabless) { |
| 243 var index = variables.indexOf(variable); |
| 244 if (index != -1) { |
| 245 return IndexAccessor.make(context, new IntLiteral(index), null, null) |
| 246 .buildAssignment(value, voidContext: voidContext); |
| 247 } |
| 248 context = new PropertyGet(context, new Name('parent')); |
| 249 } |
| 250 throw 'Unbound NestedContext.lookup($variable)'; |
| 251 } |
| 252 |
| 253 Context toNestedContext([Accessor accessor]) { |
| 254 return new NestedContext(converter, accessor ?? this.accessor, variabless); |
| 255 } |
| 256 } |
OLD | NEW |