| 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 | 7 |
| 8 import 'package:front_end/src/fasta/kernel/kernel_shadow_ast.dart' | 8 import 'package:front_end/src/fasta/kernel/kernel_shadow_ast.dart' |
| 9 show | 9 show |
| 10 KernelArguments, | 10 KernelArguments, |
| 11 KernelComplexAssign, | 11 KernelComplexAssignment, |
| 12 KernelConditionalExpression, | 12 KernelConditionalExpression, |
| 13 KernelMethodInvocation, | 13 KernelMethodInvocation, |
| 14 KernelPropertyGet, | 14 KernelPropertyGet, |
| 15 KernelPropertySet, | 15 KernelPropertySet, |
| 16 KernelVariableDeclaration, | 16 KernelVariableDeclaration, |
| 17 KernelVariableGet, | 17 KernelVariableGet, |
| 18 KernelVariableSet; | 18 KernelVariableSet; |
| 19 | 19 |
| 20 import 'package:front_end/src/fasta/kernel/utils.dart' show offsetForToken; | 20 import 'package:front_end/src/fasta/kernel/utils.dart' show offsetForToken; |
| 21 | 21 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 43 /// [Accessor] object. Later, after `= b` is parsed, [buildAssignment] will be | 43 /// [Accessor] object. Later, after `= b` is parsed, [buildAssignment] will be |
| 44 /// called. | 44 /// called. |
| 45 abstract class Accessor { | 45 abstract class Accessor { |
| 46 final BuilderHelper helper; | 46 final BuilderHelper helper; |
| 47 final Token token; | 47 final Token token; |
| 48 | 48 |
| 49 Accessor(this.helper, this.token); | 49 Accessor(this.helper, this.token); |
| 50 | 50 |
| 51 /// Builds an [Expression] representing a read from the accessor. | 51 /// Builds an [Expression] representing a read from the accessor. |
| 52 Expression buildSimpleRead() { | 52 Expression buildSimpleRead() { |
| 53 return _finish(_makeSimpleRead()); | 53 return _finish(_makeSimpleRead(), null); |
| 54 } | 54 } |
| 55 | 55 |
| 56 /// Builds an [Expression] representing an assignment with the accessor on | 56 /// Builds an [Expression] representing an assignment with the accessor on |
| 57 /// the LHS and [value] on the RHS. | 57 /// the LHS and [value] on the RHS. |
| 58 /// | 58 /// |
| 59 /// The returned expression evaluates to the assigned value, unless | 59 /// The returned expression evaluates to the assigned value, unless |
| 60 /// [voidContext] is true, in which case it may evaluate to anything. | 60 /// [voidContext] is true, in which case it may evaluate to anything. |
| 61 Expression buildAssignment(Expression value, {bool voidContext: false}) { | 61 Expression buildAssignment(Expression value, {bool voidContext: false}) { |
| 62 return _finish(_makeSimpleWrite(value, voidContext)); | 62 var complexAssignment = startComplexAssignment(value); |
| 63 return _finish(_makeSimpleWrite(value, voidContext, complexAssignment), |
| 64 complexAssignment); |
| 63 } | 65 } |
| 64 | 66 |
| 65 /// Returns an [Expression] representing a null-aware assignment (`??=`) with | 67 /// Returns an [Expression] representing a null-aware assignment (`??=`) with |
| 66 /// the accessor on the LHS and [value] on the RHS. | 68 /// the accessor on the LHS and [value] on the RHS. |
| 67 /// | 69 /// |
| 68 /// The returned expression evaluates to the assigned value, unless | 70 /// The returned expression evaluates to the assigned value, unless |
| 69 /// [voidContext] is true, in which case it may evaluate to anything. | 71 /// [voidContext] is true, in which case it may evaluate to anything. |
| 70 /// | 72 /// |
| 71 /// [type] is the static type of the RHS. | 73 /// [type] is the static type of the RHS. |
| 72 Expression buildNullAwareAssignment(Expression value, DartType type, | 74 Expression buildNullAwareAssignment(Expression value, DartType type, |
| 73 {bool voidContext: false}) { | 75 {bool voidContext: false}) { |
| 76 var complexAssignment = startComplexAssignment(value); |
| 74 if (voidContext) { | 77 if (voidContext) { |
| 75 return _finish(new KernelConditionalExpression( | 78 var nullAwareCombiner = new KernelConditionalExpression( |
| 76 buildIsNull(_makeRead()), _makeWrite(value, false), new NullLiteral(), | 79 buildIsNull(_makeRead(complexAssignment)), |
| 77 isNullAwareCombiner: true)); | 80 _makeWrite(value, false, complexAssignment), |
| 81 new NullLiteral()); |
| 82 complexAssignment?.nullAwareCombiner = nullAwareCombiner; |
| 83 return _finish(nullAwareCombiner, complexAssignment); |
| 78 } | 84 } |
| 79 var tmp = new VariableDeclaration.forValue(_makeRead()); | 85 var tmp = new VariableDeclaration.forValue(_makeRead(complexAssignment)); |
| 80 return _finish(makeLet( | 86 var nullAwareCombiner = new KernelConditionalExpression( |
| 81 tmp, | 87 buildIsNull(new VariableGet(tmp)), |
| 82 new KernelConditionalExpression(buildIsNull(new VariableGet(tmp)), | 88 _makeWrite(value, false, complexAssignment), |
| 83 _makeWrite(value, false), new VariableGet(tmp), | 89 new VariableGet(tmp)); |
| 84 isNullAwareCombiner: true))); | 90 complexAssignment?.nullAwareCombiner = nullAwareCombiner; |
| 91 return _finish(makeLet(tmp, nullAwareCombiner), complexAssignment); |
| 85 } | 92 } |
| 86 | 93 |
| 87 /// Returns an [Expression] representing a compound assignment (e.g. `+=`) | 94 /// Returns an [Expression] representing a compound assignment (e.g. `+=`) |
| 88 /// with the accessor on the LHS and [value] on the RHS. | 95 /// with the accessor on the LHS and [value] on the RHS. |
| 89 Expression buildCompoundAssignment(Name binaryOperator, Expression value, | 96 Expression buildCompoundAssignment(Name binaryOperator, Expression value, |
| 90 {int offset: TreeNode.noOffset, | 97 {int offset: TreeNode.noOffset, |
| 91 bool voidContext: false, | 98 bool voidContext: false, |
| 92 Procedure interfaceTarget}) { | 99 Procedure interfaceTarget}) { |
| 93 return _finish(_makeWrite( | 100 var complexAssignment = startComplexAssignment(value); |
| 94 makeBinary(_makeRead(), binaryOperator, interfaceTarget, value, | 101 var combiner = makeBinary( |
| 95 offset: offset, isCombiner: true), | 102 _makeRead(complexAssignment), binaryOperator, interfaceTarget, value, |
| 96 voidContext)); | 103 offset: offset); |
| 104 complexAssignment?.combiner = combiner; |
| 105 return _finish(_makeWrite(combiner, voidContext, complexAssignment), |
| 106 complexAssignment); |
| 97 } | 107 } |
| 98 | 108 |
| 99 /// Returns an [Expression] representing a pre-increment or pre-decrement | 109 /// Returns an [Expression] representing a pre-increment or pre-decrement |
| 100 /// of the accessor. | 110 /// of the accessor. |
| 101 Expression buildPrefixIncrement(Name binaryOperator, | 111 Expression buildPrefixIncrement(Name binaryOperator, |
| 102 {int offset: TreeNode.noOffset, | 112 {int offset: TreeNode.noOffset, |
| 103 bool voidContext: false, | 113 bool voidContext: false, |
| 104 Procedure interfaceTarget}) { | 114 Procedure interfaceTarget}) { |
| 105 return buildCompoundAssignment(binaryOperator, new IntLiteral(1), | 115 return buildCompoundAssignment(binaryOperator, new IntLiteral(1), |
| 106 offset: offset, | 116 offset: offset, |
| 107 voidContext: voidContext, | 117 voidContext: voidContext, |
| 108 interfaceTarget: interfaceTarget); | 118 interfaceTarget: interfaceTarget); |
| 109 } | 119 } |
| 110 | 120 |
| 111 /// Returns an [Expression] representing a post-increment or post-decrement | 121 /// Returns an [Expression] representing a post-increment or post-decrement |
| 112 /// of the accessor. | 122 /// of the accessor. |
| 113 Expression buildPostfixIncrement(Name binaryOperator, | 123 Expression buildPostfixIncrement(Name binaryOperator, |
| 114 {int offset: TreeNode.noOffset, | 124 {int offset: TreeNode.noOffset, |
| 115 bool voidContext: false, | 125 bool voidContext: false, |
| 116 Procedure interfaceTarget}) { | 126 Procedure interfaceTarget}) { |
| 117 if (voidContext) { | 127 if (voidContext) { |
| 118 return buildPrefixIncrement(binaryOperator, | 128 return buildPrefixIncrement(binaryOperator, |
| 119 offset: offset, voidContext: true, interfaceTarget: interfaceTarget); | 129 offset: offset, voidContext: true, interfaceTarget: interfaceTarget); |
| 120 } | 130 } |
| 121 var value = new VariableDeclaration.forValue(_makeRead()); | 131 var rhs = new IntLiteral(1); |
| 132 var complexAssignment = startComplexAssignment(rhs); |
| 133 var value = new VariableDeclaration.forValue(_makeRead(complexAssignment)); |
| 122 valueAccess() => new VariableGet(value); | 134 valueAccess() => new VariableGet(value); |
| 135 var combiner = makeBinary( |
| 136 valueAccess(), binaryOperator, interfaceTarget, rhs, |
| 137 offset: offset); |
| 138 complexAssignment?.combiner = combiner; |
| 139 complexAssignment?.isPostIncDec = true; |
| 123 var dummy = new KernelVariableDeclaration.forValue( | 140 var dummy = new KernelVariableDeclaration.forValue( |
| 124 _makeWrite( | 141 _makeWrite(combiner, true, complexAssignment), |
| 125 makeBinary(valueAccess(), binaryOperator, interfaceTarget, | 142 helper.functionNestingLevel); |
| 126 new IntLiteral(1), | 143 return _finish( |
| 127 offset: offset, isCombiner: true), | 144 makeLet(value, makeLet(dummy, valueAccess())), complexAssignment); |
| 128 true), | |
| 129 helper.functionNestingLevel, | |
| 130 isDiscarding: true); | |
| 131 return _finish(makeLet(value, makeLet(dummy, valueAccess()))); | |
| 132 } | 145 } |
| 133 | 146 |
| 134 Expression _makeSimpleRead() => _makeRead(); | 147 Expression _makeSimpleRead() => _makeRead(null); |
| 135 | 148 |
| 136 Expression _makeSimpleWrite(Expression value, bool voidContext) { | 149 Expression _makeSimpleWrite(Expression value, bool voidContext, |
| 137 return _makeWrite(value, voidContext); | 150 KernelComplexAssignment complexAssignment) { |
| 151 return _makeWrite(value, voidContext, complexAssignment); |
| 138 } | 152 } |
| 139 | 153 |
| 140 Expression _makeRead(); | 154 Expression _makeRead(KernelComplexAssignment complexAssignment); |
| 141 | 155 |
| 142 Expression _makeWrite(Expression value, bool voidContext); | 156 Expression _makeWrite(Expression value, bool voidContext, |
| 157 KernelComplexAssignment complexAssignment); |
| 143 | 158 |
| 144 Expression _finish(Expression body) => body; | 159 Expression _finish( |
| 160 Expression body, KernelComplexAssignment complexAssignment) => |
| 161 body; |
| 145 | 162 |
| 146 /// Returns an [Expression] representing a compile-time error. | 163 /// Returns an [Expression] representing a compile-time error. |
| 147 /// | 164 /// |
| 148 /// At runtime, an exception will be thrown. | 165 /// At runtime, an exception will be thrown. |
| 149 makeInvalidRead() { | 166 makeInvalidRead() { |
| 150 return internalError( | 167 return internalError( |
| 151 "Unhandled compile-time error.", null, offsetForToken(token)); | 168 "Unhandled compile-time error.", null, offsetForToken(token)); |
| 152 } | 169 } |
| 153 | 170 |
| 154 /// Returns an [Expression] representing a compile-time error wrapping | 171 /// Returns an [Expression] representing a compile-time error wrapping |
| 155 /// [value]. | 172 /// [value]. |
| 156 /// | 173 /// |
| 157 /// At runtime, [value] will be evaluated before throwing an exception. | 174 /// At runtime, [value] will be evaluated before throwing an exception. |
| 158 makeInvalidWrite(Expression value) { | 175 makeInvalidWrite(Expression value) { |
| 159 return internalError( | 176 return internalError( |
| 160 "Unhandled compile-time error.", null, offsetForToken(token)); | 177 "Unhandled compile-time error.", null, offsetForToken(token)); |
| 161 } | 178 } |
| 179 |
| 180 /// Creates a data structure for tracking the desugaring of a complex |
| 181 /// assignment expression whose right hand side is [rhs], if necessary, or |
| 182 /// returns `null` if not necessary. |
| 183 KernelComplexAssignment startComplexAssignment(Expression rhs) => null; |
| 162 } | 184 } |
| 163 | 185 |
| 164 abstract class VariableAccessor extends Accessor { | 186 abstract class VariableAccessor extends Accessor { |
| 165 VariableDeclaration variable; | 187 VariableDeclaration variable; |
| 166 DartType promotedType; | 188 DartType promotedType; |
| 167 | 189 |
| 168 VariableAccessor( | 190 VariableAccessor( |
| 169 BuilderHelper helper, this.variable, this.promotedType, Token token) | 191 BuilderHelper helper, this.variable, this.promotedType, Token token) |
| 170 : super(helper, token); | 192 : super(helper, token); |
| 171 | 193 |
| 172 Expression _makeRead() { | 194 Expression _makeRead(KernelComplexAssignment complexAssignment) { |
| 173 var fact = helper.typePromoter | 195 var fact = helper.typePromoter |
| 174 .getFactForAccess(variable, helper.functionNestingLevel); | 196 .getFactForAccess(variable, helper.functionNestingLevel); |
| 175 var scope = helper.typePromoter.currentScope; | 197 var scope = helper.typePromoter.currentScope; |
| 176 return new KernelVariableGet(variable, fact, scope) | 198 return new KernelVariableGet(variable, fact, scope) |
| 177 ..fileOffset = offsetForToken(token); | 199 ..fileOffset = offsetForToken(token); |
| 178 } | 200 } |
| 179 | 201 |
| 180 Expression _makeWrite(Expression value, bool voidContext) { | 202 Expression _makeWrite(Expression value, bool voidContext, |
| 203 KernelComplexAssignment complexAssignment) { |
| 181 helper.typePromoter.mutateVariable(variable, helper.functionNestingLevel); | 204 helper.typePromoter.mutateVariable(variable, helper.functionNestingLevel); |
| 182 return variable.isFinal || variable.isConst | 205 return variable.isFinal || variable.isConst |
| 183 ? makeInvalidWrite(value) | 206 ? makeInvalidWrite(value) |
| 184 : new KernelVariableSet(variable, value) | 207 : new KernelVariableSet(variable, value) |
| 185 ..fileOffset = offsetForToken(token); | 208 ..fileOffset = offsetForToken(token); |
| 186 } | 209 } |
| 187 } | 210 } |
| 188 | 211 |
| 189 class PropertyAccessor extends Accessor { | 212 class PropertyAccessor extends Accessor { |
| 190 VariableDeclaration _receiverVariable; | 213 VariableDeclaration _receiverVariable; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 203 } | 226 } |
| 204 } | 227 } |
| 205 | 228 |
| 206 PropertyAccessor.internal(BuilderHelper helper, this.receiver, this.name, | 229 PropertyAccessor.internal(BuilderHelper helper, this.receiver, this.name, |
| 207 this.getter, this.setter, Token token) | 230 this.getter, this.setter, Token token) |
| 208 : super(helper, token); | 231 : super(helper, token); |
| 209 | 232 |
| 210 Expression _makeSimpleRead() => new KernelPropertyGet(receiver, name, getter) | 233 Expression _makeSimpleRead() => new KernelPropertyGet(receiver, name, getter) |
| 211 ..fileOffset = offsetForToken(token); | 234 ..fileOffset = offsetForToken(token); |
| 212 | 235 |
| 213 Expression _makeSimpleWrite(Expression value, bool voidContext) { | 236 Expression _makeSimpleWrite(Expression value, bool voidContext, |
| 237 KernelComplexAssignment complexAssignment) { |
| 214 return new KernelPropertySet(receiver, name, value, setter) | 238 return new KernelPropertySet(receiver, name, value, setter) |
| 215 ..fileOffset = offsetForToken(token); | 239 ..fileOffset = offsetForToken(token); |
| 216 } | 240 } |
| 217 | 241 |
| 218 receiverAccess() { | 242 receiverAccess() { |
| 219 _receiverVariable ??= new VariableDeclaration.forValue(receiver); | 243 _receiverVariable ??= new VariableDeclaration.forValue(receiver); |
| 220 return new VariableGet(_receiverVariable) | 244 return new VariableGet(_receiverVariable) |
| 221 ..fileOffset = offsetForToken(token); | 245 ..fileOffset = offsetForToken(token); |
| 222 } | 246 } |
| 223 | 247 |
| 224 Expression _makeRead() => | 248 Expression _makeRead(KernelComplexAssignment complexAssignment) => |
| 225 new KernelPropertyGet(receiverAccess(), name, getter) | 249 new KernelPropertyGet(receiverAccess(), name, getter) |
| 226 ..fileOffset = offsetForToken(token); | 250 ..fileOffset = offsetForToken(token); |
| 227 | 251 |
| 228 Expression _makeWrite(Expression value, bool voidContext) { | 252 Expression _makeWrite(Expression value, bool voidContext, |
| 253 KernelComplexAssignment complexAssignment) { |
| 229 return new KernelPropertySet(receiverAccess(), name, value, setter) | 254 return new KernelPropertySet(receiverAccess(), name, value, setter) |
| 230 ..fileOffset = offsetForToken(token); | 255 ..fileOffset = offsetForToken(token); |
| 231 } | 256 } |
| 232 | 257 |
| 233 Expression _finish(Expression body) => makeLet(_receiverVariable, body); | 258 Expression _finish( |
| 259 Expression body, KernelComplexAssignment complexAssignment) => |
| 260 makeLet(_receiverVariable, body); |
| 234 } | 261 } |
| 235 | 262 |
| 236 /// Special case of [PropertyAccessor] to avoid creating an indirect access to | 263 /// Special case of [PropertyAccessor] to avoid creating an indirect access to |
| 237 /// 'this'. | 264 /// 'this'. |
| 238 class ThisPropertyAccessor extends Accessor { | 265 class ThisPropertyAccessor extends Accessor { |
| 239 Name name; | 266 Name name; |
| 240 Member getter, setter; | 267 Member getter, setter; |
| 241 | 268 |
| 242 ThisPropertyAccessor( | 269 ThisPropertyAccessor( |
| 243 BuilderHelper helper, this.name, this.getter, this.setter, Token token) | 270 BuilderHelper helper, this.name, this.getter, this.setter, Token token) |
| 244 : super(helper, token); | 271 : super(helper, token); |
| 245 | 272 |
| 246 Expression _makeRead() => | 273 Expression _makeRead(KernelComplexAssignment complexAssignment) => |
| 247 new KernelPropertyGet(new ThisExpression(), name, getter) | 274 new KernelPropertyGet(new ThisExpression(), name, getter) |
| 248 ..fileOffset = offsetForToken(token); | 275 ..fileOffset = offsetForToken(token); |
| 249 | 276 |
| 250 Expression _makeWrite(Expression value, bool voidContext) { | 277 Expression _makeWrite(Expression value, bool voidContext, |
| 278 KernelComplexAssignment complexAssignment) { |
| 251 return new KernelPropertySet(new ThisExpression(), name, value, setter) | 279 return new KernelPropertySet(new ThisExpression(), name, value, setter) |
| 252 ..fileOffset = offsetForToken(token); | 280 ..fileOffset = offsetForToken(token); |
| 253 } | 281 } |
| 254 } | 282 } |
| 255 | 283 |
| 256 class NullAwarePropertyAccessor extends Accessor { | 284 class NullAwarePropertyAccessor extends Accessor { |
| 257 VariableDeclaration receiver; | 285 VariableDeclaration receiver; |
| 258 Name name; | 286 Name name; |
| 259 Member getter, setter; | 287 Member getter, setter; |
| 260 DartType type; | 288 DartType type; |
| 261 | 289 |
| 262 NullAwarePropertyAccessor(BuilderHelper helper, Expression receiver, | 290 NullAwarePropertyAccessor(BuilderHelper helper, Expression receiver, |
| 263 this.name, this.getter, this.setter, this.type, Token token) | 291 this.name, this.getter, this.setter, this.type, Token token) |
| 264 : this.receiver = makeOrReuseVariable(receiver), | 292 : this.receiver = makeOrReuseVariable(receiver), |
| 265 super(helper, token); | 293 super(helper, token); |
| 266 | 294 |
| 267 receiverAccess() => new VariableGet(receiver); | 295 receiverAccess() => new VariableGet(receiver); |
| 268 | 296 |
| 269 Expression _makeRead() => | 297 Expression _makeRead(KernelComplexAssignment complexAssignment) => |
| 270 new KernelPropertyGet(receiverAccess(), name, getter); | 298 new KernelPropertyGet(receiverAccess(), name, getter); |
| 271 | 299 |
| 272 Expression _makeWrite(Expression value, bool voidContext) { | 300 Expression _makeWrite(Expression value, bool voidContext, |
| 301 KernelComplexAssignment complexAssignment) { |
| 273 return new KernelPropertySet(receiverAccess(), name, value, setter); | 302 return new KernelPropertySet(receiverAccess(), name, value, setter); |
| 274 } | 303 } |
| 275 | 304 |
| 276 Expression _finish(Expression body) => makeLet( | 305 Expression _finish( |
| 277 receiver, | 306 Expression body, KernelComplexAssignment complexAssignment) => |
| 278 new KernelConditionalExpression( | 307 makeLet( |
| 279 buildIsNull(receiverAccess()), new NullLiteral(), body)); | 308 receiver, |
| 309 new KernelConditionalExpression( |
| 310 buildIsNull(receiverAccess()), new NullLiteral(), body)); |
| 280 } | 311 } |
| 281 | 312 |
| 282 class SuperPropertyAccessor extends Accessor { | 313 class SuperPropertyAccessor extends Accessor { |
| 283 Name name; | 314 Name name; |
| 284 Member getter, setter; | 315 Member getter, setter; |
| 285 | 316 |
| 286 SuperPropertyAccessor( | 317 SuperPropertyAccessor( |
| 287 BuilderHelper helper, this.name, this.getter, this.setter, Token token) | 318 BuilderHelper helper, this.name, this.getter, this.setter, Token token) |
| 288 : super(helper, token); | 319 : super(helper, token); |
| 289 | 320 |
| 290 Expression _makeRead() { | 321 Expression _makeRead(KernelComplexAssignment complexAssignment) { |
| 291 if (getter == null) return makeInvalidRead(); | 322 if (getter == null) return makeInvalidRead(); |
| 292 // TODO(ahe): Use [DirectPropertyGet] when possible. | 323 // TODO(ahe): Use [DirectPropertyGet] when possible. |
| 293 return new SuperPropertyGet(name, getter) | 324 return new SuperPropertyGet(name, getter) |
| 294 ..fileOffset = offsetForToken(token); | 325 ..fileOffset = offsetForToken(token); |
| 295 } | 326 } |
| 296 | 327 |
| 297 Expression _makeWrite(Expression value, bool voidContext) { | 328 Expression _makeWrite(Expression value, bool voidContext, |
| 329 KernelComplexAssignment complexAssignment) { |
| 298 if (setter == null) return makeInvalidWrite(value); | 330 if (setter == null) return makeInvalidWrite(value); |
| 299 // TODO(ahe): Use [DirectPropertySet] when possible. | 331 // TODO(ahe): Use [DirectPropertySet] when possible. |
| 300 return new SuperPropertySet(name, value, setter) | 332 return new SuperPropertySet(name, value, setter) |
| 301 ..fileOffset = offsetForToken(token); | 333 ..fileOffset = offsetForToken(token); |
| 302 } | 334 } |
| 303 } | 335 } |
| 304 | 336 |
| 305 class IndexAccessor extends Accessor { | 337 class IndexAccessor extends Accessor { |
| 306 Expression receiver; | 338 Expression receiver; |
| 307 Expression index; | 339 Expression index; |
| 308 VariableDeclaration receiverVariable; | 340 VariableDeclaration receiverVariable; |
| 309 VariableDeclaration indexVariable; | 341 VariableDeclaration indexVariable; |
| 310 Procedure getter, setter; | 342 Procedure getter, setter; |
| 311 | 343 |
| 312 static Accessor make(BuilderHelper helper, Expression receiver, | 344 static Accessor make(BuilderHelper helper, Expression receiver, |
| 313 Expression index, Procedure getter, Procedure setter, | 345 Expression index, Procedure getter, Procedure setter, |
| 314 {Token token}) { | 346 {Token token}) { |
| 315 if (receiver is ThisExpression) { | 347 if (receiver is ThisExpression) { |
| 316 return new ThisIndexAccessor(helper, index, getter, setter, token); | 348 return new ThisIndexAccessor(helper, index, getter, setter, token); |
| 317 } else { | 349 } else { |
| 318 return new IndexAccessor.internal( | 350 return new IndexAccessor.internal( |
| 319 helper, receiver, index, getter, setter, token); | 351 helper, receiver, index, getter, setter, token); |
| 320 } | 352 } |
| 321 } | 353 } |
| 322 | 354 |
| 323 IndexAccessor.internal(BuilderHelper helper, this.receiver, this.index, | 355 IndexAccessor.internal(BuilderHelper helper, this.receiver, this.index, |
| 324 this.getter, this.setter, Token token) | 356 this.getter, this.setter, Token token) |
| 325 : super(helper, token); | 357 : super(helper, token); |
| 326 | 358 |
| 327 Expression _makeSimpleRead() => new KernelMethodInvocation( | 359 Expression _makeSimpleRead() { |
| 328 receiver, indexGetName, new KernelArguments(<Expression>[index]), | 360 var read = new KernelMethodInvocation( |
| 329 interfaceTarget: getter) | 361 receiver, indexGetName, new KernelArguments(<Expression>[index]), |
| 330 ..fileOffset = offsetForToken(token); | 362 interfaceTarget: getter) |
| 363 ..fileOffset = offsetForToken(token); |
| 364 return read; |
| 365 } |
| 331 | 366 |
| 332 Expression _makeSimpleWrite(Expression value, bool voidContext) { | 367 Expression _makeSimpleWrite(Expression value, bool voidContext, |
| 333 if (!voidContext) return _makeWriteAndReturn(value); | 368 KernelComplexAssignment complexAssignment) { |
| 334 return new KernelMethodInvocation( | 369 if (!voidContext) return _makeWriteAndReturn(value, complexAssignment); |
| 370 var write = new KernelMethodInvocation( |
| 335 receiver, indexSetName, new KernelArguments(<Expression>[index, value]), | 371 receiver, indexSetName, new KernelArguments(<Expression>[index, value]), |
| 336 interfaceTarget: setter) | 372 interfaceTarget: setter) |
| 337 ..fileOffset = offsetForToken(token); | 373 ..fileOffset = offsetForToken(token); |
| 374 complexAssignment?.write = write; |
| 375 return write; |
| 338 } | 376 } |
| 339 | 377 |
| 340 receiverAccess() { | 378 receiverAccess() { |
| 341 // We cannot reuse the receiver if it is a variable since it might be | 379 // We cannot reuse the receiver if it is a variable since it might be |
| 342 // reassigned in the index expression. | 380 // reassigned in the index expression. |
| 343 receiverVariable ??= new VariableDeclaration.forValue(receiver); | 381 receiverVariable ??= new VariableDeclaration.forValue(receiver); |
| 344 return new VariableGet(receiverVariable) | 382 return new VariableGet(receiverVariable) |
| 345 ..fileOffset = offsetForToken(token); | 383 ..fileOffset = offsetForToken(token); |
| 346 } | 384 } |
| 347 | 385 |
| 348 indexAccess() { | 386 indexAccess() { |
| 349 indexVariable ??= new VariableDeclaration.forValue(index); | 387 indexVariable ??= new VariableDeclaration.forValue(index); |
| 350 return new VariableGet(indexVariable)..fileOffset = offsetForToken(token); | 388 return new VariableGet(indexVariable)..fileOffset = offsetForToken(token); |
| 351 } | 389 } |
| 352 | 390 |
| 353 Expression _makeRead() { | 391 Expression _makeRead(KernelComplexAssignment complexAssignment) { |
| 354 return new KernelMethodInvocation(receiverAccess(), indexGetName, | 392 var read = new KernelMethodInvocation(receiverAccess(), indexGetName, |
| 355 new KernelArguments(<Expression>[indexAccess()]), | 393 new KernelArguments(<Expression>[indexAccess()]), |
| 356 interfaceTarget: getter) | 394 interfaceTarget: getter) |
| 357 ..fileOffset = offsetForToken(token); | 395 ..fileOffset = offsetForToken(token); |
| 396 complexAssignment?.read = read; |
| 397 return read; |
| 358 } | 398 } |
| 359 | 399 |
| 360 Expression _makeWrite(Expression value, bool voidContext) { | 400 Expression _makeWrite(Expression value, bool voidContext, |
| 361 if (!voidContext) return _makeWriteAndReturn(value); | 401 KernelComplexAssignment complexAssignment) { |
| 362 return new KernelMethodInvocation(receiverAccess(), indexSetName, | 402 if (!voidContext) return _makeWriteAndReturn(value, complexAssignment); |
| 403 var write = new KernelMethodInvocation(receiverAccess(), indexSetName, |
| 363 new KernelArguments(<Expression>[indexAccess(), value]), | 404 new KernelArguments(<Expression>[indexAccess(), value]), |
| 364 interfaceTarget: setter) | 405 interfaceTarget: setter) |
| 365 ..fileOffset = offsetForToken(token); | 406 ..fileOffset = offsetForToken(token); |
| 407 complexAssignment?.write = write; |
| 408 return write; |
| 366 } | 409 } |
| 367 | 410 |
| 368 // TODO(dmitryas): remove this method after the "[]=" operator of the Context | 411 // TODO(dmitryas): remove this method after the "[]=" operator of the Context |
| 369 // class is made to return a value. | 412 // class is made to return a value. |
| 370 _makeWriteAndReturn(Expression value) { | 413 _makeWriteAndReturn( |
| 414 Expression value, KernelComplexAssignment complexAssignment) { |
| 371 // The call to []= does not return the value like direct-style assignments | 415 // The call to []= does not return the value like direct-style assignments |
| 372 // do. We need to bind the value in a let. | 416 // do. We need to bind the value in a let. |
| 373 var valueVariable = new VariableDeclaration.forValue(value); | 417 var valueVariable = new VariableDeclaration.forValue(value); |
| 418 var write = new KernelMethodInvocation( |
| 419 receiverAccess(), |
| 420 indexSetName, |
| 421 new KernelArguments( |
| 422 <Expression>[indexAccess(), new VariableGet(valueVariable)]), |
| 423 interfaceTarget: setter) |
| 424 ..fileOffset = offsetForToken(token); |
| 425 complexAssignment?.write = write; |
| 374 var dummy = new KernelVariableDeclaration.forValue( | 426 var dummy = new KernelVariableDeclaration.forValue( |
| 375 new KernelMethodInvocation( | 427 write, helper.functionNestingLevel); |
| 376 receiverAccess(), | |
| 377 indexSetName, | |
| 378 new KernelArguments( | |
| 379 <Expression>[indexAccess(), new VariableGet(valueVariable)]), | |
| 380 interfaceTarget: setter) | |
| 381 ..fileOffset = offsetForToken(token), | |
| 382 helper.functionNestingLevel, | |
| 383 isDiscarding: true); | |
| 384 return makeLet( | 428 return makeLet( |
| 385 valueVariable, makeLet(dummy, new VariableGet(valueVariable))); | 429 valueVariable, makeLet(dummy, new VariableGet(valueVariable))); |
| 386 } | 430 } |
| 387 | 431 |
| 388 Expression _finish(Expression body) { | 432 Expression _finish( |
| 389 if (receiverVariable == null) { | 433 Expression body, KernelComplexAssignment complexAssignment) { |
| 390 assert(indexVariable == null); | 434 Expression desugared = |
| 391 return body; | 435 makeLet(receiverVariable, makeLet(indexVariable, body)); |
| 436 if (complexAssignment != null) { |
| 437 complexAssignment.desugared = desugared; |
| 438 return complexAssignment; |
| 392 } else { | 439 } else { |
| 393 return new KernelComplexAssign( | 440 return desugared; |
| 394 receiverVariable, makeLet(indexVariable, body)); | |
| 395 } | 441 } |
| 396 } | 442 } |
| 397 } | 443 } |
| 398 | 444 |
| 399 /// Special case of [IndexAccessor] to avoid creating an indirect access to | 445 /// Special case of [IndexAccessor] to avoid creating an indirect access to |
| 400 /// 'this'. | 446 /// 'this'. |
| 401 class ThisIndexAccessor extends Accessor { | 447 class ThisIndexAccessor extends Accessor { |
| 402 Expression index; | 448 Expression index; |
| 403 VariableDeclaration indexVariable; | 449 VariableDeclaration indexVariable; |
| 404 Procedure getter, setter; | 450 Procedure getter, setter; |
| 405 | 451 |
| 406 ThisIndexAccessor( | 452 ThisIndexAccessor( |
| 407 BuilderHelper helper, this.index, this.getter, this.setter, Token token) | 453 BuilderHelper helper, this.index, this.getter, this.setter, Token token) |
| 408 : super(helper, token); | 454 : super(helper, token); |
| 409 | 455 |
| 410 Expression _makeSimpleRead() { | 456 Expression _makeSimpleRead() { |
| 411 return new KernelMethodInvocation(new ThisExpression(), indexGetName, | 457 return new KernelMethodInvocation(new ThisExpression(), indexGetName, |
| 412 new KernelArguments(<Expression>[index]), | 458 new KernelArguments(<Expression>[index]), |
| 413 interfaceTarget: getter); | 459 interfaceTarget: getter); |
| 414 } | 460 } |
| 415 | 461 |
| 416 Expression _makeSimpleWrite(Expression value, bool voidContext) { | 462 Expression _makeSimpleWrite(Expression value, bool voidContext, |
| 463 KernelComplexAssignment complexAssignment) { |
| 417 if (!voidContext) return _makeWriteAndReturn(value); | 464 if (!voidContext) return _makeWriteAndReturn(value); |
| 418 return new KernelMethodInvocation(new ThisExpression(), indexSetName, | 465 return new KernelMethodInvocation(new ThisExpression(), indexSetName, |
| 419 new KernelArguments(<Expression>[index, value]), | 466 new KernelArguments(<Expression>[index, value]), |
| 420 interfaceTarget: setter); | 467 interfaceTarget: setter); |
| 421 } | 468 } |
| 422 | 469 |
| 423 indexAccess() { | 470 indexAccess() { |
| 424 indexVariable ??= new VariableDeclaration.forValue(index); | 471 indexVariable ??= new VariableDeclaration.forValue(index); |
| 425 return new VariableGet(indexVariable); | 472 return new VariableGet(indexVariable); |
| 426 } | 473 } |
| 427 | 474 |
| 428 Expression _makeRead() => new KernelMethodInvocation(new ThisExpression(), | 475 Expression _makeRead(KernelComplexAssignment complexAssignment) => |
| 429 indexGetName, new KernelArguments(<Expression>[indexAccess()]), | 476 new KernelMethodInvocation(new ThisExpression(), indexGetName, |
| 430 interfaceTarget: getter); | 477 new KernelArguments(<Expression>[indexAccess()]), |
| 478 interfaceTarget: getter); |
| 431 | 479 |
| 432 Expression _makeWrite(Expression value, bool voidContext) { | 480 Expression _makeWrite(Expression value, bool voidContext, |
| 481 KernelComplexAssignment complexAssignment) { |
| 433 if (!voidContext) return _makeWriteAndReturn(value); | 482 if (!voidContext) return _makeWriteAndReturn(value); |
| 434 return new KernelMethodInvocation(new ThisExpression(), indexSetName, | 483 return new KernelMethodInvocation(new ThisExpression(), indexSetName, |
| 435 new KernelArguments(<Expression>[indexAccess(), value]), | 484 new KernelArguments(<Expression>[indexAccess(), value]), |
| 436 interfaceTarget: setter); | 485 interfaceTarget: setter); |
| 437 } | 486 } |
| 438 | 487 |
| 439 _makeWriteAndReturn(Expression value) { | 488 _makeWriteAndReturn(Expression value) { |
| 440 var valueVariable = new VariableDeclaration.forValue(value); | 489 var valueVariable = new VariableDeclaration.forValue(value); |
| 441 var dummy = new VariableDeclaration.forValue(new KernelMethodInvocation( | 490 var dummy = new VariableDeclaration.forValue(new KernelMethodInvocation( |
| 442 new ThisExpression(), | 491 new ThisExpression(), |
| 443 indexSetName, | 492 indexSetName, |
| 444 new KernelArguments( | 493 new KernelArguments( |
| 445 <Expression>[indexAccess(), new VariableGet(valueVariable)]), | 494 <Expression>[indexAccess(), new VariableGet(valueVariable)]), |
| 446 interfaceTarget: setter)); | 495 interfaceTarget: setter)); |
| 447 return makeLet( | 496 return makeLet( |
| 448 valueVariable, makeLet(dummy, new VariableGet(valueVariable))); | 497 valueVariable, makeLet(dummy, new VariableGet(valueVariable))); |
| 449 } | 498 } |
| 450 | 499 |
| 451 Expression _finish(Expression body) => makeLet(indexVariable, body); | 500 Expression _finish( |
| 501 Expression body, KernelComplexAssignment complexAssignment) => |
| 502 makeLet(indexVariable, body); |
| 452 } | 503 } |
| 453 | 504 |
| 454 class SuperIndexAccessor extends Accessor { | 505 class SuperIndexAccessor extends Accessor { |
| 455 Expression index; | 506 Expression index; |
| 456 VariableDeclaration indexVariable; | 507 VariableDeclaration indexVariable; |
| 457 Member getter, setter; | 508 Member getter, setter; |
| 458 | 509 |
| 459 SuperIndexAccessor( | 510 SuperIndexAccessor( |
| 460 BuilderHelper helper, this.index, this.getter, this.setter, Token token) | 511 BuilderHelper helper, this.index, this.getter, this.setter, Token token) |
| 461 : super(helper, token); | 512 : super(helper, token); |
| 462 | 513 |
| 463 indexAccess() { | 514 indexAccess() { |
| 464 indexVariable ??= new VariableDeclaration.forValue(index); | 515 indexVariable ??= new VariableDeclaration.forValue(index); |
| 465 return new VariableGet(indexVariable); | 516 return new VariableGet(indexVariable); |
| 466 } | 517 } |
| 467 | 518 |
| 468 Expression _makeSimpleRead() => new SuperMethodInvocation( | 519 Expression _makeSimpleRead() => new SuperMethodInvocation( |
| 469 indexGetName, new KernelArguments(<Expression>[index]), getter); | 520 indexGetName, new KernelArguments(<Expression>[index]), getter); |
| 470 | 521 |
| 471 Expression _makeSimpleWrite(Expression value, bool voidContext) { | 522 Expression _makeSimpleWrite(Expression value, bool voidContext, |
| 523 KernelComplexAssignment complexAssignment) { |
| 472 if (!voidContext) return _makeWriteAndReturn(value); | 524 if (!voidContext) return _makeWriteAndReturn(value); |
| 473 return new SuperMethodInvocation( | 525 return new SuperMethodInvocation( |
| 474 indexSetName, new KernelArguments(<Expression>[index, value]), setter); | 526 indexSetName, new KernelArguments(<Expression>[index, value]), setter); |
| 475 } | 527 } |
| 476 | 528 |
| 477 Expression _makeRead() { | 529 Expression _makeRead(KernelComplexAssignment complexAssignment) { |
| 478 return new SuperMethodInvocation( | 530 return new SuperMethodInvocation( |
| 479 indexGetName, new KernelArguments(<Expression>[indexAccess()]), getter); | 531 indexGetName, new KernelArguments(<Expression>[indexAccess()]), getter); |
| 480 } | 532 } |
| 481 | 533 |
| 482 Expression _makeWrite(Expression value, bool voidContext) { | 534 Expression _makeWrite(Expression value, bool voidContext, |
| 535 KernelComplexAssignment complexAssignment) { |
| 483 if (!voidContext) return _makeWriteAndReturn(value); | 536 if (!voidContext) return _makeWriteAndReturn(value); |
| 484 return new SuperMethodInvocation(indexSetName, | 537 return new SuperMethodInvocation(indexSetName, |
| 485 new KernelArguments(<Expression>[indexAccess(), value]), setter); | 538 new KernelArguments(<Expression>[indexAccess(), value]), setter); |
| 486 } | 539 } |
| 487 | 540 |
| 488 _makeWriteAndReturn(Expression value) { | 541 _makeWriteAndReturn(Expression value) { |
| 489 var valueVariable = new VariableDeclaration.forValue(value); | 542 var valueVariable = new VariableDeclaration.forValue(value); |
| 490 var dummy = new VariableDeclaration.forValue(new SuperMethodInvocation( | 543 var dummy = new VariableDeclaration.forValue(new SuperMethodInvocation( |
| 491 indexSetName, | 544 indexSetName, |
| 492 new KernelArguments( | 545 new KernelArguments( |
| 493 <Expression>[indexAccess(), new VariableGet(valueVariable)]), | 546 <Expression>[indexAccess(), new VariableGet(valueVariable)]), |
| 494 setter)); | 547 setter)); |
| 495 return makeLet( | 548 return makeLet( |
| 496 valueVariable, makeLet(dummy, new VariableGet(valueVariable))); | 549 valueVariable, makeLet(dummy, new VariableGet(valueVariable))); |
| 497 } | 550 } |
| 498 | 551 |
| 499 Expression _finish(Expression body) { | 552 Expression _finish( |
| 553 Expression body, KernelComplexAssignment complexAssignment) { |
| 500 return makeLet(indexVariable, body); | 554 return makeLet(indexVariable, body); |
| 501 } | 555 } |
| 502 } | 556 } |
| 503 | 557 |
| 504 class StaticAccessor extends Accessor { | 558 class StaticAccessor extends Accessor { |
| 505 Member readTarget; | 559 Member readTarget; |
| 506 Member writeTarget; | 560 Member writeTarget; |
| 507 | 561 |
| 508 StaticAccessor( | 562 StaticAccessor( |
| 509 BuilderHelper helper, this.readTarget, this.writeTarget, Token token) | 563 BuilderHelper helper, this.readTarget, this.writeTarget, Token token) |
| 510 : super(helper, token); | 564 : super(helper, token); |
| 511 | 565 |
| 512 Expression _makeRead() => readTarget == null | 566 Expression _makeRead(KernelComplexAssignment complexAssignment) => |
| 513 ? makeInvalidRead() | 567 readTarget == null |
| 514 : helper.makeStaticGet(readTarget, token); | 568 ? makeInvalidRead() |
| 569 : helper.makeStaticGet(readTarget, token); |
| 515 | 570 |
| 516 Expression _makeWrite(Expression value, bool voidContext) { | 571 Expression _makeWrite(Expression value, bool voidContext, |
| 572 KernelComplexAssignment complexAssignment) { |
| 517 return writeTarget == null | 573 return writeTarget == null |
| 518 ? makeInvalidWrite(value) | 574 ? makeInvalidWrite(value) |
| 519 : new StaticSet(writeTarget, value) | 575 : new StaticSet(writeTarget, value) |
| 520 ..fileOffset = offsetForToken(token); | 576 ..fileOffset = offsetForToken(token); |
| 521 } | 577 } |
| 522 } | 578 } |
| 523 | 579 |
| 524 class ReadOnlyAccessor extends Accessor { | 580 class ReadOnlyAccessor extends Accessor { |
| 525 Expression expression; | 581 Expression expression; |
| 526 VariableDeclaration value; | 582 VariableDeclaration value; |
| 527 | 583 |
| 528 ReadOnlyAccessor(BuilderHelper helper, this.expression, Token token) | 584 ReadOnlyAccessor(BuilderHelper helper, this.expression, Token token) |
| 529 : super(helper, token); | 585 : super(helper, token); |
| 530 | 586 |
| 531 Expression _makeSimpleRead() => expression; | 587 Expression _makeSimpleRead() => expression; |
| 532 | 588 |
| 533 Expression _makeRead() { | 589 Expression _makeRead(KernelComplexAssignment complexAssignment) { |
| 534 value ??= new VariableDeclaration.forValue(expression); | 590 value ??= new VariableDeclaration.forValue(expression); |
| 535 return new VariableGet(value); | 591 return new VariableGet(value); |
| 536 } | 592 } |
| 537 | 593 |
| 538 Expression _makeWrite(Expression value, bool voidContext) => | 594 Expression _makeWrite(Expression value, bool voidContext, |
| 595 KernelComplexAssignment complexAssignment) => |
| 539 makeInvalidWrite(value); | 596 makeInvalidWrite(value); |
| 540 | 597 |
| 541 Expression _finish(Expression body) => makeLet(value, body); | 598 Expression _finish( |
| 599 Expression body, KernelComplexAssignment complexAssignment) => |
| 600 makeLet(value, body); |
| 542 } | 601 } |
| 543 | 602 |
| 544 Expression makeLet(VariableDeclaration variable, Expression body) { | 603 Expression makeLet(VariableDeclaration variable, Expression body) { |
| 545 if (variable == null) return body; | 604 if (variable == null) return body; |
| 546 return new Let(variable, body); | 605 return new Let(variable, body); |
| 547 } | 606 } |
| 548 | 607 |
| 549 Expression makeBinary( | 608 Expression makeBinary( |
| 550 Expression left, Name operator, Procedure interfaceTarget, Expression right, | 609 Expression left, Name operator, Procedure interfaceTarget, Expression right, |
| 551 {int offset: TreeNode.noOffset, bool isCombiner: false}) { | 610 {int offset: TreeNode.noOffset}) { |
| 552 return new KernelMethodInvocation( | 611 return new KernelMethodInvocation( |
| 553 left, operator, new KernelArguments(<Expression>[right]), | 612 left, operator, new KernelArguments(<Expression>[right]), |
| 554 interfaceTarget: interfaceTarget, isCombiner: isCombiner) | 613 interfaceTarget: interfaceTarget) |
| 555 ..fileOffset = offset; | 614 ..fileOffset = offset; |
| 556 } | 615 } |
| 557 | 616 |
| 558 Expression buildIsNull(Expression value, {int offset: TreeNode.noOffset}) { | 617 Expression buildIsNull(Expression value, {int offset: TreeNode.noOffset}) { |
| 559 return makeBinary(value, equalsName, null, new NullLiteral(), offset: offset); | 618 return makeBinary(value, equalsName, null, new NullLiteral(), offset: offset); |
| 560 } | 619 } |
| 561 | 620 |
| 562 VariableDeclaration makeOrReuseVariable(Expression value) { | 621 VariableDeclaration makeOrReuseVariable(Expression value) { |
| 563 // TODO: Devise a way to remember if a variable declaration was reused | 622 // TODO: Devise a way to remember if a variable declaration was reused |
| 564 // or is fresh (hence needs a let binding). | 623 // or is fresh (hence needs a let binding). |
| 565 return new VariableDeclaration.forValue(value); | 624 return new VariableDeclaration.forValue(value); |
| 566 } | 625 } |
| OLD | NEW |