| OLD | NEW |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 /// A library to help transform compounds and null-aware accessors into | 5 /// A library to help transform compounds and null-aware accessors into |
| 6 /// let expressions. | 6 /// let expressions. |
| 7 library kernel.frontend.accessors; | 7 library kernel.frontend.accessors; |
| 8 | 8 |
| 9 import '../ast.dart'; | 9 import '../ast.dart'; |
| 10 | 10 |
| 11 final Name indexGetName = new Name("[]"); |
| 12 |
| 13 final Name indexSetName = new Name("[]="); |
| 14 |
| 15 /// An [Accessor] represents a subexpression for which we can't yet build a |
| 16 /// kernel [Expression] because we don't yet know the context in which it is |
| 17 /// used. |
| 18 /// |
| 19 /// Once the context is known, an [Accessor] can be converted into an |
| 20 /// [Expression] by calling a "build" method. |
| 21 /// |
| 22 /// For example, when building a kernel representation for `a[x] = b`, after |
| 23 /// parsing `a[x]` but before parsing `= b`, we don't yet know whether to |
| 24 /// generate an invocation of `operator[]` or `operator[]=`, so we generate an |
| 25 /// [Accessor] object. Later, after `= b` is parsed, [buildAssignment] will be |
| 26 /// called. |
| 11 abstract class Accessor { | 27 abstract class Accessor { |
| 28 final int offset; |
| 29 |
| 12 // [builtBinary] and [builtGetter] capture the inner nodes. Used by | 30 // [builtBinary] and [builtGetter] capture the inner nodes. Used by |
| 13 // dart2js+rasta for determining how subexpressions map to legacy dart2js Ast | 31 // dart2js+rasta for determining how subexpressions map to legacy dart2js Ast |
| 14 // nodes. This will be removed once dart2js type analysis (aka inference) is | 32 // nodes. This will be removed once dart2js type analysis (aka inference) is |
| 15 // reimplemented on kernel. | 33 // reimplemented on kernel. |
| 16 Expression builtBinary; | 34 Expression builtBinary; |
| 17 Expression builtGetter; | 35 Expression builtGetter; |
| 18 | 36 |
| 37 Accessor(this.offset); |
| 38 |
| 39 /// Builds an [Expression] representing a read from the accessor. |
| 19 Expression buildSimpleRead() { | 40 Expression buildSimpleRead() { |
| 20 return _finish(_makeSimpleRead()); | 41 return _finish(_makeSimpleRead()); |
| 21 } | 42 } |
| 22 | 43 |
| 23 /// Returns an assignment to the accessor. | 44 /// Builds an [Expression] representing an assignment with the accessor on |
| 45 /// the LHS and [value] on the RHS. |
| 24 /// | 46 /// |
| 25 /// The returned expression evaluates to the assigned value, unless | 47 /// The returned expression evaluates to the assigned value, unless |
| 26 /// [voidContext] is true, in which case it may evaluate to anything. | 48 /// [voidContext] is true, in which case it may evaluate to anything. |
| 27 Expression buildAssignment(Expression value, {bool voidContext: false}) { | 49 Expression buildAssignment(Expression value, {bool voidContext: false}) { |
| 28 return _finish(_makeSimpleWrite(value, voidContext)); | 50 return _finish(_makeSimpleWrite(value, voidContext)); |
| 29 } | 51 } |
| 30 | 52 |
| 53 /// Returns an [Expression] representing a null-aware assignment (`??=`) with |
| 54 /// the accessor on the LHS and [value] on the RHS. |
| 55 /// |
| 56 /// The returned expression evaluates to the assigned value, unless |
| 57 /// [voidContext] is true, in which case it may evaluate to anything. |
| 58 /// |
| 59 /// [type] is the static type of the RHS. |
| 31 Expression buildNullAwareAssignment(Expression value, DartType type, | 60 Expression buildNullAwareAssignment(Expression value, DartType type, |
| 32 {bool voidContext: false}) { | 61 {bool voidContext: false}) { |
| 33 if (voidContext) { | 62 if (voidContext) { |
| 34 return _finish(new ConditionalExpression(buildIsNull(_makeRead()), | 63 return _finish(new ConditionalExpression(buildIsNull(_makeRead()), |
| 35 _makeWrite(value, false), new NullLiteral(), type)); | 64 _makeWrite(value, false), new NullLiteral(), type)); |
| 36 } | 65 } |
| 37 var tmp = new VariableDeclaration.forValue(_makeRead()); | 66 var tmp = new VariableDeclaration.forValue(_makeRead()); |
| 38 return _finish(makeLet( | 67 return _finish(makeLet( |
| 39 tmp, | 68 tmp, |
| 40 new ConditionalExpression(buildIsNull(new VariableGet(tmp)), | 69 new ConditionalExpression(buildIsNull(new VariableGet(tmp)), |
| 41 _makeWrite(value, false), new VariableGet(tmp), type))); | 70 _makeWrite(value, false), new VariableGet(tmp), type))); |
| 42 } | 71 } |
| 43 | 72 |
| 73 /// Returns an [Expression] representing a compound assignment (e.g. `+=`) |
| 74 /// with the accessor on the LHS and [value] on the RHS. |
| 44 Expression buildCompoundAssignment(Name binaryOperator, Expression value, | 75 Expression buildCompoundAssignment(Name binaryOperator, Expression value, |
| 45 {int offset: TreeNode.noOffset, | 76 {int offset: TreeNode.noOffset, |
| 46 bool voidContext: false, | 77 bool voidContext: false, |
| 47 Procedure interfaceTarget}) { | 78 Procedure interfaceTarget}) { |
| 48 return _finish(_makeWrite( | 79 return _finish(_makeWrite( |
| 49 builtBinary = makeBinary( | 80 builtBinary = makeBinary( |
| 50 _makeRead(), binaryOperator, interfaceTarget, value, | 81 _makeRead(), binaryOperator, interfaceTarget, value, |
| 51 offset: offset), | 82 offset: offset), |
| 52 voidContext)); | 83 voidContext)); |
| 53 } | 84 } |
| 54 | 85 |
| 86 /// Returns an [Expression] representing a pre-increment or pre-decrement |
| 87 /// of the accessor. |
| 55 Expression buildPrefixIncrement(Name binaryOperator, | 88 Expression buildPrefixIncrement(Name binaryOperator, |
| 56 {int offset: TreeNode.noOffset, | 89 {int offset: TreeNode.noOffset, |
| 57 bool voidContext: false, | 90 bool voidContext: false, |
| 58 Procedure interfaceTarget}) { | 91 Procedure interfaceTarget}) { |
| 59 return buildCompoundAssignment(binaryOperator, new IntLiteral(1), | 92 return buildCompoundAssignment(binaryOperator, new IntLiteral(1), |
| 60 offset: offset, | 93 offset: offset, |
| 61 voidContext: voidContext, | 94 voidContext: voidContext, |
| 62 interfaceTarget: interfaceTarget); | 95 interfaceTarget: interfaceTarget); |
| 63 } | 96 } |
| 64 | 97 |
| 98 /// Returns an [Expression] representing a post-increment or post-decrement |
| 99 /// of the accessor. |
| 65 Expression buildPostfixIncrement(Name binaryOperator, | 100 Expression buildPostfixIncrement(Name binaryOperator, |
| 66 {int offset: TreeNode.noOffset, | 101 {int offset: TreeNode.noOffset, |
| 67 bool voidContext: false, | 102 bool voidContext: false, |
| 68 Procedure interfaceTarget}) { | 103 Procedure interfaceTarget}) { |
| 69 if (voidContext) { | 104 if (voidContext) { |
| 70 return buildPrefixIncrement(binaryOperator, | 105 return buildPrefixIncrement(binaryOperator, |
| 71 offset: offset, voidContext: true, interfaceTarget: interfaceTarget); | 106 offset: offset, voidContext: true, interfaceTarget: interfaceTarget); |
| 72 } | 107 } |
| 73 var value = new VariableDeclaration.forValue(_makeRead()); | 108 var value = new VariableDeclaration.forValue(_makeRead()); |
| 74 valueAccess() => new VariableGet(value); | 109 valueAccess() => new VariableGet(value); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 85 Expression _makeSimpleWrite(Expression value, bool voidContext) { | 120 Expression _makeSimpleWrite(Expression value, bool voidContext) { |
| 86 return _makeWrite(value, voidContext); | 121 return _makeWrite(value, voidContext); |
| 87 } | 122 } |
| 88 | 123 |
| 89 Expression _makeRead(); | 124 Expression _makeRead(); |
| 90 | 125 |
| 91 Expression _makeWrite(Expression value, bool voidContext); | 126 Expression _makeWrite(Expression value, bool voidContext); |
| 92 | 127 |
| 93 Expression _finish(Expression body) => body; | 128 Expression _finish(Expression body) => body; |
| 94 | 129 |
| 130 /// Returns an [Expression] representing a compile-time error. |
| 131 /// |
| 132 /// At runtime, an exception will be thrown. |
| 95 makeInvalidRead() => new InvalidExpression(); | 133 makeInvalidRead() => new InvalidExpression(); |
| 96 | 134 |
| 135 /// Returns an [Expression] representing a compile-time error wrapping |
| 136 /// [value]. |
| 137 /// |
| 138 /// At runtime, [value] will be evaluated before throwing an exception. |
| 97 makeInvalidWrite(Expression value) => wrapInvalid(value); | 139 makeInvalidWrite(Expression value) => wrapInvalid(value); |
| 98 } | 140 } |
| 99 | 141 |
| 100 class VariableAccessor extends Accessor { | 142 class VariableAccessor extends Accessor { |
| 101 VariableDeclaration variable; | 143 VariableDeclaration variable; |
| 102 DartType promotedType; | 144 DartType promotedType; |
| 103 | 145 |
| 104 VariableAccessor(this.variable, [this.promotedType]); | 146 VariableAccessor(this.variable, this.promotedType, int offset) |
| 147 : super(offset); |
| 105 | 148 |
| 106 _makeRead() => new VariableGet(variable, promotedType); | 149 _makeRead() => new VariableGet(variable, promotedType)..fileOffset = offset; |
| 107 | 150 |
| 108 _makeWrite(Expression value, bool voidContext) { | 151 _makeWrite(Expression value, bool voidContext) { |
| 109 return variable.isFinal || variable.isConst | 152 return variable.isFinal || variable.isConst |
| 110 ? makeInvalidWrite(value) | 153 ? makeInvalidWrite(value) |
| 111 : new VariableSet(variable, value); | 154 : new VariableSet(variable, value)..fileOffset = offset; |
| 112 } | 155 } |
| 113 } | 156 } |
| 114 | 157 |
| 115 class PropertyAccessor extends Accessor { | 158 class PropertyAccessor extends Accessor { |
| 116 VariableDeclaration _receiverVariable; | 159 VariableDeclaration _receiverVariable; |
| 117 Expression receiver; | 160 Expression receiver; |
| 118 Name name; | 161 Name name; |
| 119 Member getter, setter; | 162 Member getter, setter; |
| 120 | 163 |
| 121 static Accessor make( | 164 static Accessor make( |
| 122 Expression receiver, Name name, Member getter, Member setter) { | 165 Expression receiver, Name name, Member getter, Member setter, |
| 166 {int offset: TreeNode.noOffset}) { |
| 123 if (receiver is ThisExpression) { | 167 if (receiver is ThisExpression) { |
| 124 return new ThisPropertyAccessor(name, getter, setter); | 168 return new ThisPropertyAccessor(name, getter, setter, offset); |
| 125 } else { | 169 } else { |
| 126 return new PropertyAccessor._internal(receiver, name, getter, setter); | 170 return new PropertyAccessor.internal( |
| 171 receiver, name, getter, setter, offset); |
| 127 } | 172 } |
| 128 } | 173 } |
| 129 | 174 |
| 130 PropertyAccessor._internal( | 175 PropertyAccessor.internal( |
| 131 this.receiver, this.name, this.getter, this.setter); | 176 this.receiver, this.name, this.getter, this.setter, int offset) |
| 177 : super(offset); |
| 132 | 178 |
| 133 _makeSimpleRead() => new PropertyGet(receiver, name, getter); | 179 _makeSimpleRead() => |
| 180 new PropertyGet(receiver, name, getter)..fileOffset = offset; |
| 181 |
| 134 _makeSimpleWrite(Expression value, bool voidContext) { | 182 _makeSimpleWrite(Expression value, bool voidContext) { |
| 135 return new PropertySet(receiver, name, value, setter); | 183 return new PropertySet(receiver, name, value, setter)..fileOffset = offset; |
| 136 } | 184 } |
| 137 | 185 |
| 138 receiverAccess() { | 186 receiverAccess() { |
| 139 _receiverVariable ??= new VariableDeclaration.forValue(receiver); | 187 _receiverVariable ??= new VariableDeclaration.forValue(receiver); |
| 140 return new VariableGet(_receiverVariable); | 188 return new VariableGet(_receiverVariable)..fileOffset = offset; |
| 141 } | 189 } |
| 142 | 190 |
| 143 _makeRead() => builtGetter = new PropertyGet(receiverAccess(), name, getter); | 191 _makeRead() => builtGetter = new PropertyGet(receiverAccess(), name, getter) |
| 192 ..fileOffset = offset; |
| 144 | 193 |
| 145 _makeWrite(Expression value, bool voidContext) { | 194 _makeWrite(Expression value, bool voidContext) { |
| 146 return new PropertySet(receiverAccess(), name, value, setter); | 195 return new PropertySet(receiverAccess(), name, value, setter) |
| 196 ..fileOffset = offset; |
| 147 } | 197 } |
| 148 | 198 |
| 149 _finish(Expression body) => makeLet(_receiverVariable, body); | 199 _finish(Expression body) => makeLet(_receiverVariable, body); |
| 150 } | 200 } |
| 151 | 201 |
| 152 /// Special case of [PropertyAccessor] to avoid creating an indirect access to | 202 /// Special case of [PropertyAccessor] to avoid creating an indirect access to |
| 153 /// 'this'. | 203 /// 'this'. |
| 154 class ThisPropertyAccessor extends Accessor { | 204 class ThisPropertyAccessor extends Accessor { |
| 155 Name name; | 205 Name name; |
| 156 Member getter, setter; | 206 Member getter, setter; |
| 157 | 207 |
| 158 ThisPropertyAccessor(this.name, this.getter, this.setter); | 208 ThisPropertyAccessor(this.name, this.getter, this.setter, int offset) |
| 209 : super(offset); |
| 159 | 210 |
| 160 _makeRead() => | 211 _makeRead() => builtGetter = |
| 161 builtGetter = new PropertyGet(new ThisExpression(), name, getter); | 212 new PropertyGet(new ThisExpression(), name, getter)..fileOffset = offset; |
| 162 | 213 |
| 163 _makeWrite(Expression value, bool voidContext) { | 214 _makeWrite(Expression value, bool voidContext) { |
| 164 return new PropertySet(new ThisExpression(), name, value, setter); | 215 return new PropertySet(new ThisExpression(), name, value, setter) |
| 216 ..fileOffset = offset; |
| 165 } | 217 } |
| 166 } | 218 } |
| 167 | 219 |
| 168 class NullAwarePropertyAccessor extends Accessor { | 220 class NullAwarePropertyAccessor extends Accessor { |
| 169 VariableDeclaration receiver; | 221 VariableDeclaration receiver; |
| 170 Name name; | 222 Name name; |
| 171 Member getter, setter; | 223 Member getter, setter; |
| 172 DartType type; | 224 DartType type; |
| 173 | 225 |
| 174 NullAwarePropertyAccessor( | 226 NullAwarePropertyAccessor(Expression receiver, this.name, this.getter, |
| 175 Expression receiver, this.name, this.getter, this.setter, this.type) | 227 this.setter, this.type, int offset) |
| 176 : this.receiver = makeOrReuseVariable(receiver); | 228 : this.receiver = makeOrReuseVariable(receiver), |
| 229 super(offset); |
| 177 | 230 |
| 178 receiverAccess() => new VariableGet(receiver); | 231 receiverAccess() => new VariableGet(receiver); |
| 179 | 232 |
| 180 _makeRead() => builtGetter = new PropertyGet(receiverAccess(), name, getter); | 233 _makeRead() => builtGetter = new PropertyGet(receiverAccess(), name, getter); |
| 181 | 234 |
| 182 _makeWrite(Expression value, bool voidContext) { | 235 _makeWrite(Expression value, bool voidContext) { |
| 183 return new PropertySet(receiverAccess(), name, value, setter); | 236 return new PropertySet(receiverAccess(), name, value, setter); |
| 184 } | 237 } |
| 185 | 238 |
| 186 _finish(Expression body) => makeLet( | 239 _finish(Expression body) => makeLet( |
| 187 receiver, | 240 receiver, |
| 188 new ConditionalExpression( | 241 new ConditionalExpression( |
| 189 buildIsNull(receiverAccess()), new NullLiteral(), body, type)); | 242 buildIsNull(receiverAccess()), new NullLiteral(), body, type)); |
| 190 } | 243 } |
| 191 | 244 |
| 192 class SuperPropertyAccessor extends Accessor { | 245 class SuperPropertyAccessor extends Accessor { |
| 193 Name name; | 246 Name name; |
| 194 Member getter, setter; | 247 Member getter, setter; |
| 195 | 248 |
| 196 SuperPropertyAccessor(this.name, this.getter, this.setter); | 249 SuperPropertyAccessor(this.name, this.getter, this.setter, int offset) |
| 250 : super(offset); |
| 197 | 251 |
| 198 _makeRead() => builtGetter = new SuperPropertyGet(name, getter); | 252 _makeRead() { |
| 253 if (getter == null) return makeInvalidRead(); |
| 254 // TODO(ahe): Use [DirectPropertyGet] when possible. |
| 255 return builtGetter = new SuperPropertyGet(name, getter) |
| 256 ..fileOffset = offset; |
| 257 } |
| 199 | 258 |
| 200 _makeWrite(Expression value, bool voidContext) { | 259 _makeWrite(Expression value, bool voidContext) { |
| 201 return new SuperPropertySet(name, value, setter); | 260 if (setter == null) return makeInvalidWrite(value); |
| 261 // TODO(ahe): Use [DirectPropertySet] when possible. |
| 262 return new SuperPropertySet(name, value, setter)..fileOffset = offset; |
| 202 } | 263 } |
| 203 } | 264 } |
| 204 | 265 |
| 205 final Name _indexGet = new Name('[]'); | |
| 206 final Name _indexSet = new Name('[]='); | |
| 207 | |
| 208 class IndexAccessor extends Accessor { | 266 class IndexAccessor extends Accessor { |
| 209 Expression receiver; | 267 Expression receiver; |
| 210 Expression index; | 268 Expression index; |
| 211 VariableDeclaration receiverVariable; | 269 VariableDeclaration receiverVariable; |
| 212 VariableDeclaration indexVariable; | 270 VariableDeclaration indexVariable; |
| 213 Procedure getter, setter; | 271 Procedure getter, setter; |
| 214 | 272 |
| 215 static Accessor make(Expression receiver, Expression index, Procedure getter, | 273 static Accessor make( |
| 216 Procedure setter) { | 274 Expression receiver, Expression index, Procedure getter, Procedure setter, |
| 275 {int offset: TreeNode.noOffset}) { |
| 217 if (receiver is ThisExpression) { | 276 if (receiver is ThisExpression) { |
| 218 return new ThisIndexAccessor(index, getter, setter); | 277 return new ThisIndexAccessor(index, getter, setter, offset); |
| 219 } else { | 278 } else { |
| 220 return new IndexAccessor._internal(receiver, index, getter, setter); | 279 return new IndexAccessor.internal( |
| 280 receiver, index, getter, setter, offset); |
| 221 } | 281 } |
| 222 } | 282 } |
| 223 | 283 |
| 224 IndexAccessor._internal(this.receiver, this.index, this.getter, this.setter); | 284 IndexAccessor.internal( |
| 285 this.receiver, this.index, this.getter, this.setter, int offset) |
| 286 : super(offset); |
| 225 | 287 |
| 226 _makeSimpleRead() => new MethodInvocation( | 288 _makeSimpleRead() => new MethodInvocation( |
| 227 receiver, _indexGet, new Arguments(<Expression>[index]), getter); | 289 receiver, indexGetName, new Arguments(<Expression>[index]), getter) |
| 290 ..fileOffset = offset; |
| 228 | 291 |
| 229 _makeSimpleWrite(Expression value, bool voidContext) { | 292 _makeSimpleWrite(Expression value, bool voidContext) { |
| 230 if (!voidContext) return _makeWriteAndReturn(value); | 293 if (!voidContext) return _makeWriteAndReturn(value); |
| 231 return new MethodInvocation( | 294 return new MethodInvocation(receiver, indexSetName, |
| 232 receiver, _indexSet, new Arguments(<Expression>[index, value]), setter); | 295 new Arguments(<Expression>[index, value]), setter)..fileOffset = offset; |
| 233 } | 296 } |
| 234 | 297 |
| 235 receiverAccess() { | 298 receiverAccess() { |
| 236 // We cannot reuse the receiver if it is a variable since it might be | 299 // We cannot reuse the receiver if it is a variable since it might be |
| 237 // reassigned in the index expression. | 300 // reassigned in the index expression. |
| 238 receiverVariable ??= new VariableDeclaration.forValue(receiver); | 301 receiverVariable ??= new VariableDeclaration.forValue(receiver); |
| 239 return new VariableGet(receiverVariable); | 302 return new VariableGet(receiverVariable)..fileOffset = offset; |
| 240 } | 303 } |
| 241 | 304 |
| 242 indexAccess() { | 305 indexAccess() { |
| 243 indexVariable ??= new VariableDeclaration.forValue(index); | 306 indexVariable ??= new VariableDeclaration.forValue(index); |
| 244 return new VariableGet(indexVariable); | 307 return new VariableGet(indexVariable)..fileOffset = offset; |
| 245 } | 308 } |
| 246 | 309 |
| 247 _makeRead() { | 310 _makeRead() { |
| 248 return builtGetter = new MethodInvocation(receiverAccess(), _indexGet, | 311 return builtGetter = new MethodInvocation( |
| 249 new Arguments(<Expression>[indexAccess()]), getter); | 312 receiverAccess(), |
| 313 indexGetName, |
| 314 new Arguments(<Expression>[indexAccess()]), |
| 315 getter)..fileOffset = offset; |
| 250 } | 316 } |
| 251 | 317 |
| 252 _makeWrite(Expression value, bool voidContext) { | 318 _makeWrite(Expression value, bool voidContext) { |
| 253 if (!voidContext) return _makeWriteAndReturn(value); | 319 if (!voidContext) return _makeWriteAndReturn(value); |
| 254 return new MethodInvocation(receiverAccess(), _indexSet, | 320 return new MethodInvocation( |
| 255 new Arguments(<Expression>[indexAccess(), value]), setter); | 321 receiverAccess(), |
| 322 indexSetName, |
| 323 new Arguments(<Expression>[indexAccess(), value]), |
| 324 setter)..fileOffset = offset; |
| 256 } | 325 } |
| 257 | 326 |
| 258 _makeWriteAndReturn(Expression value) { | 327 _makeWriteAndReturn(Expression value) { |
| 259 // The call to []= does not return the value like direct-style assignments | 328 // The call to []= does not return the value like direct-style assignments |
| 260 // do. We need to bind the value in a let. | 329 // do. We need to bind the value in a let. |
| 261 var valueVariable = new VariableDeclaration.forValue(value); | 330 var valueVariable = new VariableDeclaration.forValue(value); |
| 262 var dummy = new VariableDeclaration.forValue(new MethodInvocation( | 331 var dummy = new VariableDeclaration.forValue(new MethodInvocation( |
| 263 receiverAccess(), | 332 receiverAccess(), |
| 264 _indexSet, | 333 indexSetName, |
| 265 new Arguments( | 334 new Arguments( |
| 266 <Expression>[indexAccess(), new VariableGet(valueVariable)]), | 335 <Expression>[indexAccess(), new VariableGet(valueVariable)]), |
| 267 setter)); | 336 setter)..fileOffset = offset); |
| 268 return makeLet( | 337 return makeLet( |
| 269 valueVariable, makeLet(dummy, new VariableGet(valueVariable))); | 338 valueVariable, makeLet(dummy, new VariableGet(valueVariable))); |
| 270 } | 339 } |
| 271 | 340 |
| 272 Expression _finish(Expression body) { | 341 Expression _finish(Expression body) { |
| 273 return makeLet(receiverVariable, makeLet(indexVariable, body)); | 342 return makeLet(receiverVariable, makeLet(indexVariable, body)); |
| 274 } | 343 } |
| 275 } | 344 } |
| 276 | 345 |
| 277 /// Special case of [IndexAccessor] to avoid creating an indirect access to | 346 /// Special case of [IndexAccessor] to avoid creating an indirect access to |
| 278 /// 'this'. | 347 /// 'this'. |
| 279 class ThisIndexAccessor extends Accessor { | 348 class ThisIndexAccessor extends Accessor { |
| 280 Expression index; | 349 Expression index; |
| 281 VariableDeclaration indexVariable; | 350 VariableDeclaration indexVariable; |
| 282 Procedure getter, setter; | 351 Procedure getter, setter; |
| 283 | 352 |
| 284 ThisIndexAccessor(this.index, this.getter, this.setter); | 353 ThisIndexAccessor(this.index, this.getter, this.setter, int offset) |
| 354 : super(offset); |
| 285 | 355 |
| 286 _makeSimpleRead() { | 356 _makeSimpleRead() { |
| 287 return new MethodInvocation(new ThisExpression(), _indexGet, | 357 return new MethodInvocation(new ThisExpression(), indexGetName, |
| 288 new Arguments(<Expression>[index]), getter); | 358 new Arguments(<Expression>[index]), getter); |
| 289 } | 359 } |
| 290 | 360 |
| 291 _makeSimpleWrite(Expression value, bool voidContext) { | 361 _makeSimpleWrite(Expression value, bool voidContext) { |
| 292 if (!voidContext) return _makeWriteAndReturn(value); | 362 if (!voidContext) return _makeWriteAndReturn(value); |
| 293 return new MethodInvocation(new ThisExpression(), _indexSet, | 363 return new MethodInvocation(new ThisExpression(), indexSetName, |
| 294 new Arguments(<Expression>[index, value]), setter); | 364 new Arguments(<Expression>[index, value]), setter); |
| 295 } | 365 } |
| 296 | 366 |
| 297 indexAccess() { | 367 indexAccess() { |
| 298 indexVariable ??= new VariableDeclaration.forValue(index); | 368 indexVariable ??= new VariableDeclaration.forValue(index); |
| 299 return new VariableGet(indexVariable); | 369 return new VariableGet(indexVariable); |
| 300 } | 370 } |
| 301 | 371 |
| 302 _makeRead() => builtGetter = new MethodInvocation(new ThisExpression(), | 372 _makeRead() => builtGetter = new MethodInvocation(new ThisExpression(), |
| 303 _indexGet, new Arguments(<Expression>[indexAccess()]), getter); | 373 indexGetName, new Arguments(<Expression>[indexAccess()]), getter); |
| 304 | 374 |
| 305 _makeWrite(Expression value, bool voidContext) { | 375 _makeWrite(Expression value, bool voidContext) { |
| 306 if (!voidContext) return _makeWriteAndReturn(value); | 376 if (!voidContext) return _makeWriteAndReturn(value); |
| 307 return new MethodInvocation(new ThisExpression(), _indexSet, | 377 return new MethodInvocation(new ThisExpression(), indexSetName, |
| 308 new Arguments(<Expression>[indexAccess(), value]), setter); | 378 new Arguments(<Expression>[indexAccess(), value]), setter); |
| 309 } | 379 } |
| 310 | 380 |
| 311 _makeWriteAndReturn(Expression value) { | 381 _makeWriteAndReturn(Expression value) { |
| 312 var valueVariable = new VariableDeclaration.forValue(value); | 382 var valueVariable = new VariableDeclaration.forValue(value); |
| 313 var dummy = new VariableDeclaration.forValue(new MethodInvocation( | 383 var dummy = new VariableDeclaration.forValue(new MethodInvocation( |
| 314 new ThisExpression(), | 384 new ThisExpression(), |
| 315 _indexSet, | 385 indexSetName, |
| 316 new Arguments( | 386 new Arguments( |
| 317 <Expression>[indexAccess(), new VariableGet(valueVariable)]), | 387 <Expression>[indexAccess(), new VariableGet(valueVariable)]), |
| 318 setter)); | 388 setter)); |
| 319 return makeLet( | 389 return makeLet( |
| 320 valueVariable, makeLet(dummy, new VariableGet(valueVariable))); | 390 valueVariable, makeLet(dummy, new VariableGet(valueVariable))); |
| 321 } | 391 } |
| 322 | 392 |
| 323 Expression _finish(Expression body) => makeLet(indexVariable, body); | 393 Expression _finish(Expression body) => makeLet(indexVariable, body); |
| 324 } | 394 } |
| 325 | 395 |
| 326 class SuperIndexAccessor extends Accessor { | 396 class SuperIndexAccessor extends Accessor { |
| 327 Expression index; | 397 Expression index; |
| 328 VariableDeclaration indexVariable; | 398 VariableDeclaration indexVariable; |
| 329 Member getter, setter; | 399 Member getter, setter; |
| 330 | 400 |
| 331 SuperIndexAccessor(this.index, this.getter, this.setter); | 401 SuperIndexAccessor(this.index, this.getter, this.setter, int offset) |
| 402 : super(offset); |
| 332 | 403 |
| 333 indexAccess() { | 404 indexAccess() { |
| 334 indexVariable ??= new VariableDeclaration.forValue(index); | 405 indexVariable ??= new VariableDeclaration.forValue(index); |
| 335 return new VariableGet(indexVariable); | 406 return new VariableGet(indexVariable); |
| 336 } | 407 } |
| 337 | 408 |
| 338 _makeSimpleRead() => new SuperMethodInvocation( | 409 _makeSimpleRead() => new SuperMethodInvocation( |
| 339 _indexGet, new Arguments(<Expression>[index]), getter); | 410 indexGetName, new Arguments(<Expression>[index]), getter); |
| 340 | 411 |
| 341 _makeSimpleWrite(Expression value, bool voidContext) { | 412 _makeSimpleWrite(Expression value, bool voidContext) { |
| 342 if (!voidContext) return _makeWriteAndReturn(value); | 413 if (!voidContext) return _makeWriteAndReturn(value); |
| 343 return new SuperMethodInvocation( | 414 return new SuperMethodInvocation( |
| 344 _indexSet, new Arguments(<Expression>[index, value]), setter); | 415 indexSetName, new Arguments(<Expression>[index, value]), setter); |
| 345 } | 416 } |
| 346 | 417 |
| 347 _makeRead() { | 418 _makeRead() { |
| 348 return builtGetter = new SuperMethodInvocation( | 419 return builtGetter = new SuperMethodInvocation( |
| 349 _indexGet, new Arguments(<Expression>[indexAccess()]), getter); | 420 indexGetName, new Arguments(<Expression>[indexAccess()]), getter); |
| 350 } | 421 } |
| 351 | 422 |
| 352 _makeWrite(Expression value, bool voidContext) { | 423 _makeWrite(Expression value, bool voidContext) { |
| 353 if (!voidContext) return _makeWriteAndReturn(value); | 424 if (!voidContext) return _makeWriteAndReturn(value); |
| 354 return new SuperMethodInvocation( | 425 return new SuperMethodInvocation(indexSetName, |
| 355 _indexSet, new Arguments(<Expression>[indexAccess(), value]), setter); | 426 new Arguments(<Expression>[indexAccess(), value]), setter); |
| 356 } | 427 } |
| 357 | 428 |
| 358 _makeWriteAndReturn(Expression value) { | 429 _makeWriteAndReturn(Expression value) { |
| 359 var valueVariable = new VariableDeclaration.forValue(value); | 430 var valueVariable = new VariableDeclaration.forValue(value); |
| 360 var dummy = new VariableDeclaration.forValue(new SuperMethodInvocation( | 431 var dummy = new VariableDeclaration.forValue(new SuperMethodInvocation( |
| 361 _indexSet, | 432 indexSetName, |
| 362 new Arguments( | 433 new Arguments( |
| 363 <Expression>[indexAccess(), new VariableGet(valueVariable)]), | 434 <Expression>[indexAccess(), new VariableGet(valueVariable)]), |
| 364 setter)); | 435 setter)); |
| 365 return makeLet( | 436 return makeLet( |
| 366 valueVariable, makeLet(dummy, new VariableGet(valueVariable))); | 437 valueVariable, makeLet(dummy, new VariableGet(valueVariable))); |
| 367 } | 438 } |
| 368 | 439 |
| 369 Expression _finish(Expression body) { | 440 Expression _finish(Expression body) { |
| 370 return makeLet(indexVariable, body); | 441 return makeLet(indexVariable, body); |
| 371 } | 442 } |
| 372 } | 443 } |
| 373 | 444 |
| 374 class StaticAccessor extends Accessor { | 445 class StaticAccessor extends Accessor { |
| 375 Member readTarget; | 446 Member readTarget; |
| 376 Member writeTarget; | 447 Member writeTarget; |
| 377 | 448 |
| 378 StaticAccessor(this.readTarget, this.writeTarget); | 449 StaticAccessor(this.readTarget, this.writeTarget, int offset) : super(offset); |
| 379 | 450 |
| 380 _makeRead() => builtGetter = | 451 _makeRead() => builtGetter = readTarget == null |
| 381 readTarget == null ? makeInvalidRead() : new StaticGet(readTarget); | 452 ? makeInvalidRead() |
| 453 : new StaticGet(readTarget)..fileOffset = offset; |
| 382 | 454 |
| 383 _makeWrite(Expression value, bool voidContext) { | 455 _makeWrite(Expression value, bool voidContext) { |
| 384 return writeTarget == null | 456 return writeTarget == null |
| 385 ? makeInvalidWrite(value) | 457 ? makeInvalidWrite(value) |
| 386 : new StaticSet(writeTarget, value); | 458 : new StaticSet(writeTarget, value)..fileOffset = offset; |
| 387 } | 459 } |
| 388 } | 460 } |
| 389 | 461 |
| 390 class ReadOnlyAccessor extends Accessor { | 462 class ReadOnlyAccessor extends Accessor { |
| 391 Expression expression; | 463 Expression expression; |
| 392 VariableDeclaration value; | 464 VariableDeclaration value; |
| 393 | 465 |
| 394 ReadOnlyAccessor(this.expression); | 466 ReadOnlyAccessor(this.expression, int offset) : super(offset); |
| 395 | 467 |
| 396 _makeSimpleRead() => expression; | 468 _makeSimpleRead() => expression; |
| 397 | 469 |
| 398 _makeRead() { | 470 _makeRead() { |
| 399 value ??= new VariableDeclaration.forValue(expression); | 471 value ??= new VariableDeclaration.forValue(expression); |
| 400 return new VariableGet(value); | 472 return new VariableGet(value); |
| 401 } | 473 } |
| 402 | 474 |
| 403 _makeWrite(Expression value, bool voidContext) => makeInvalidWrite(value); | 475 _makeWrite(Expression value, bool voidContext) => makeInvalidWrite(value); |
| 404 | 476 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 427 | 499 |
| 428 VariableDeclaration makeOrReuseVariable(Expression value) { | 500 VariableDeclaration makeOrReuseVariable(Expression value) { |
| 429 // TODO: Devise a way to remember if a variable declaration was reused | 501 // TODO: Devise a way to remember if a variable declaration was reused |
| 430 // or is fresh (hence needs a let binding). | 502 // or is fresh (hence needs a let binding). |
| 431 return new VariableDeclaration.forValue(value); | 503 return new VariableDeclaration.forValue(value); |
| 432 } | 504 } |
| 433 | 505 |
| 434 Expression wrapInvalid(Expression e) { | 506 Expression wrapInvalid(Expression e) { |
| 435 return new Let(new VariableDeclaration.forValue(e), new InvalidExpression()); | 507 return new Let(new VariableDeclaration.forValue(e), new InvalidExpression()); |
| 436 } | 508 } |
| OLD | NEW |