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 // Note: copied from package:kernel at revision 7346348. |
| 6 |
| 7 /// A library to help transform compounds and null-aware accessors into |
| 8 /// let expressions. |
| 9 library kernel.frontend.accessors; |
| 10 |
| 11 import 'package:kernel/ast.dart'; |
| 12 |
| 13 abstract class Accessor { |
| 14 Expression buildSimpleRead() { |
| 15 return _finish(_makeSimpleRead()); |
| 16 } |
| 17 |
| 18 /// Returns an assignment to the accessor. |
| 19 /// |
| 20 /// The returned expression evaluates to the assigned value, unless |
| 21 /// [voidContext] is true, in which case it may evaluate to anything. |
| 22 Expression buildAssignment(Expression value, {bool voidContext: false}) { |
| 23 return _finish(_makeSimpleWrite(value, voidContext)); |
| 24 } |
| 25 |
| 26 Expression buildNullAwareAssignment(Expression value, DartType type, |
| 27 {bool voidContext: false}) { |
| 28 if (voidContext) { |
| 29 return _finish(new ConditionalExpression(buildIsNull(_makeRead()), |
| 30 _makeWrite(value, voidContext), new NullLiteral(), type)); |
| 31 } |
| 32 var tmp = new VariableDeclaration.forValue(_makeRead()); |
| 33 return _finish(makeLet( |
| 34 tmp, |
| 35 new ConditionalExpression(buildIsNull(new VariableGet(tmp)), |
| 36 _makeWrite(value, voidContext), new VariableGet(tmp), type))); |
| 37 } |
| 38 |
| 39 Expression buildCompoundAssignment(Name binaryOperator, Expression value, |
| 40 {bool voidContext: false, Procedure interfaceTarget}) { |
| 41 return _finish(_makeWrite( |
| 42 makeBinary(_makeRead(), binaryOperator, interfaceTarget, value), |
| 43 voidContext)); |
| 44 } |
| 45 |
| 46 Expression buildPrefixIncrement(Name binaryOperator, |
| 47 {bool voidContext: false, Procedure interfaceTarget}) { |
| 48 return buildCompoundAssignment(binaryOperator, new IntLiteral(1), |
| 49 voidContext: voidContext, interfaceTarget: interfaceTarget); |
| 50 } |
| 51 |
| 52 Expression buildPostfixIncrement(Name binaryOperator, |
| 53 {bool voidContext: false, Procedure interfaceTarget}) { |
| 54 if (voidContext) { |
| 55 return buildPrefixIncrement(binaryOperator, |
| 56 voidContext: true, interfaceTarget: interfaceTarget); |
| 57 } |
| 58 var value = new VariableDeclaration.forValue(_makeRead()); |
| 59 valueAccess() => new VariableGet(value); |
| 60 var dummy = new VariableDeclaration.forValue(_makeWrite( |
| 61 makeBinary( |
| 62 valueAccess(), binaryOperator, interfaceTarget, new IntLiteral(1)), |
| 63 true)); |
| 64 return _finish(makeLet(value, makeLet(dummy, valueAccess()))); |
| 65 } |
| 66 |
| 67 Expression _makeSimpleRead() => _makeRead(); |
| 68 |
| 69 Expression _makeSimpleWrite(Expression value, bool voidContext) { |
| 70 return _makeWrite(value, voidContext); |
| 71 } |
| 72 |
| 73 Expression _makeRead(); |
| 74 |
| 75 Expression _makeWrite(Expression value, bool voidContext); |
| 76 |
| 77 Expression _finish(Expression body) => body; |
| 78 |
| 79 makeInvalidRead() => new InvalidExpression(); |
| 80 |
| 81 makeInvalidWrite(Expression value) => wrapInvalid(value); |
| 82 } |
| 83 |
| 84 class VariableAccessor extends Accessor { |
| 85 VariableDeclaration variable; |
| 86 DartType promotedType; |
| 87 |
| 88 VariableAccessor(this.variable, [this.promotedType]); |
| 89 |
| 90 VariableAccessor.internal(this.variable, this.promotedType); |
| 91 |
| 92 _makeRead() => new VariableGet(variable, promotedType); |
| 93 |
| 94 _makeWrite(Expression value, bool voidContext) { |
| 95 return variable.isFinal || variable.isConst |
| 96 ? makeInvalidWrite(value) |
| 97 : new VariableSet(variable, value); |
| 98 } |
| 99 } |
| 100 |
| 101 class PropertyAccessor extends Accessor { |
| 102 VariableDeclaration _receiverVariable; |
| 103 Expression receiver; |
| 104 Name name; |
| 105 Member getter, setter; |
| 106 |
| 107 static Accessor make( |
| 108 Expression receiver, Name name, Member getter, Member setter) { |
| 109 if (receiver is ThisExpression) { |
| 110 return new ThisPropertyAccessor(name, getter, setter); |
| 111 } else { |
| 112 return new PropertyAccessor.internal(receiver, name, getter, setter); |
| 113 } |
| 114 } |
| 115 |
| 116 PropertyAccessor.internal( |
| 117 this.receiver, this.name, this.getter, this.setter); |
| 118 |
| 119 _makeSimpleRead() => new PropertyGet(receiver, name, getter); |
| 120 _makeSimpleWrite(Expression value, bool voidContext) { |
| 121 return new PropertySet(receiver, name, value, setter); |
| 122 } |
| 123 |
| 124 receiverAccess() { |
| 125 _receiverVariable ??= new VariableDeclaration.forValue(receiver); |
| 126 return new VariableGet(_receiverVariable); |
| 127 } |
| 128 |
| 129 _makeRead() => new PropertyGet(receiverAccess(), name, getter); |
| 130 |
| 131 _makeWrite(Expression value, bool voidContext) { |
| 132 return new PropertySet(receiverAccess(), name, value, setter); |
| 133 } |
| 134 |
| 135 _finish(Expression body) => makeLet(_receiverVariable, body); |
| 136 } |
| 137 |
| 138 /// Special case of [PropertyAccessor] to avoid creating an indirect access to |
| 139 /// 'this'. |
| 140 class ThisPropertyAccessor extends Accessor { |
| 141 Name name; |
| 142 Member getter, setter; |
| 143 |
| 144 ThisPropertyAccessor(this.name, this.getter, this.setter); |
| 145 |
| 146 _makeRead() => new PropertyGet(new ThisExpression(), name, getter); |
| 147 |
| 148 _makeWrite(Expression value, bool voidContext) { |
| 149 return new PropertySet(new ThisExpression(), name, value, setter); |
| 150 } |
| 151 } |
| 152 |
| 153 class NullAwarePropertyAccessor extends Accessor { |
| 154 VariableDeclaration receiver; |
| 155 Name name; |
| 156 Member getter, setter; |
| 157 DartType type; |
| 158 |
| 159 NullAwarePropertyAccessor( |
| 160 Expression receiver, this.name, this.getter, this.setter, this.type) |
| 161 : this.receiver = makeOrReuseVariable(receiver); |
| 162 |
| 163 receiverAccess() => new VariableGet(receiver); |
| 164 |
| 165 _makeRead() => new PropertyGet(receiverAccess(), name, getter); |
| 166 |
| 167 _makeWrite(Expression value, bool voidContext) { |
| 168 return new PropertySet(receiverAccess(), name, value, setter); |
| 169 } |
| 170 |
| 171 _finish(Expression body) => makeLet( |
| 172 receiver, |
| 173 new ConditionalExpression( |
| 174 buildIsNull(receiverAccess()), new NullLiteral(), body, type)); |
| 175 } |
| 176 |
| 177 class SuperPropertyAccessor extends Accessor { |
| 178 Name name; |
| 179 Member getter, setter; |
| 180 |
| 181 SuperPropertyAccessor(this.name, this.getter, this.setter); |
| 182 |
| 183 _makeRead() { |
| 184 if (getter == null) return makeInvalidRead(); |
| 185 // TODO(ahe): Use [DirectPropertyGet] when possible. |
| 186 Expression result = new DirectPropertyGet(new ThisExpression(), getter); |
| 187 result = new SuperPropertyGet(name, getter); |
| 188 return result; |
| 189 } |
| 190 |
| 191 _makeWrite(Expression value, bool voidContext) { |
| 192 if (setter == null) return makeInvalidWrite(value); |
| 193 // TODO(ahe): Use [DirectPropertySet] when possible. |
| 194 Expression result = |
| 195 new DirectPropertySet(new ThisExpression(), setter, value); |
| 196 result = new SuperPropertySet(name, value, setter); |
| 197 return result; |
| 198 } |
| 199 } |
| 200 |
| 201 final Name _indexGet = new Name('[]'); |
| 202 final Name _indexSet = new Name('[]='); |
| 203 |
| 204 class IndexAccessor extends Accessor { |
| 205 Expression receiver; |
| 206 Expression index; |
| 207 VariableDeclaration receiverVariable; |
| 208 VariableDeclaration indexVariable; |
| 209 Procedure getter, setter; |
| 210 |
| 211 static Accessor make(Expression receiver, Expression index, Procedure getter, |
| 212 Procedure setter) { |
| 213 if (receiver is ThisExpression) { |
| 214 return new ThisIndexAccessor(index, getter, setter); |
| 215 } else { |
| 216 return new IndexAccessor.internal(receiver, index, getter, setter); |
| 217 } |
| 218 } |
| 219 |
| 220 IndexAccessor.internal(this.receiver, this.index, this.getter, this.setter); |
| 221 |
| 222 _makeSimpleRead() => new MethodInvocation( |
| 223 receiver, _indexGet, new Arguments(<Expression>[index]), getter); |
| 224 |
| 225 _makeSimpleWrite(Expression value, bool voidContext) { |
| 226 if (!voidContext) return _makeWriteAndReturn(value); |
| 227 return new MethodInvocation( |
| 228 receiver, _indexSet, new Arguments(<Expression>[index, value]), setter); |
| 229 } |
| 230 |
| 231 receiverAccess() { |
| 232 // We cannot reuse the receiver if it is a variable since it might be |
| 233 // reassigned in the index expression. |
| 234 receiverVariable ??= new VariableDeclaration.forValue(receiver); |
| 235 return new VariableGet(receiverVariable); |
| 236 } |
| 237 |
| 238 indexAccess() { |
| 239 indexVariable ??= new VariableDeclaration.forValue(index); |
| 240 return new VariableGet(indexVariable); |
| 241 } |
| 242 |
| 243 _makeRead() { |
| 244 return new MethodInvocation(receiverAccess(), _indexGet, |
| 245 new Arguments(<Expression>[indexAccess()]), getter); |
| 246 } |
| 247 |
| 248 _makeWrite(Expression value, bool voidContext) { |
| 249 if (!voidContext) return _makeWriteAndReturn(value); |
| 250 return new MethodInvocation(receiverAccess(), _indexSet, |
| 251 new Arguments(<Expression>[indexAccess(), value]), setter); |
| 252 } |
| 253 |
| 254 _makeWriteAndReturn(Expression value) { |
| 255 // The call to []= does not return the value like direct-style assignments |
| 256 // do. We need to bind the value in a let. |
| 257 var valueVariable = new VariableDeclaration.forValue(value); |
| 258 var dummy = new VariableDeclaration.forValue(new MethodInvocation( |
| 259 receiverAccess(), |
| 260 _indexSet, |
| 261 new Arguments( |
| 262 <Expression>[indexAccess(), new VariableGet(valueVariable)]), |
| 263 setter)); |
| 264 return makeLet( |
| 265 valueVariable, makeLet(dummy, new VariableGet(valueVariable))); |
| 266 } |
| 267 |
| 268 Expression _finish(Expression body) { |
| 269 return makeLet(receiverVariable, makeLet(indexVariable, body)); |
| 270 } |
| 271 } |
| 272 |
| 273 /// Special case of [IndexAccessor] to avoid creating an indirect access to |
| 274 /// 'this'. |
| 275 class ThisIndexAccessor extends Accessor { |
| 276 Expression index; |
| 277 VariableDeclaration indexVariable; |
| 278 Procedure getter, setter; |
| 279 |
| 280 ThisIndexAccessor(this.index, this.getter, this.setter); |
| 281 |
| 282 _makeSimpleRead() { |
| 283 return new MethodInvocation(new ThisExpression(), _indexGet, |
| 284 new Arguments(<Expression>[index]), getter); |
| 285 } |
| 286 |
| 287 _makeSimpleWrite(Expression value, bool voidContext) { |
| 288 if (!voidContext) return _makeWriteAndReturn(value); |
| 289 return new MethodInvocation(new ThisExpression(), _indexSet, |
| 290 new Arguments(<Expression>[index, value]), setter); |
| 291 } |
| 292 |
| 293 indexAccess() { |
| 294 indexVariable ??= new VariableDeclaration.forValue(index); |
| 295 return new VariableGet(indexVariable); |
| 296 } |
| 297 |
| 298 _makeRead() => new MethodInvocation(new ThisExpression(), _indexGet, |
| 299 new Arguments(<Expression>[indexAccess()]), getter); |
| 300 |
| 301 _makeWrite(Expression value, bool voidContext) { |
| 302 if (!voidContext) return _makeWriteAndReturn(value); |
| 303 return new MethodInvocation(new ThisExpression(), _indexSet, |
| 304 new Arguments(<Expression>[indexAccess(), value]), setter); |
| 305 } |
| 306 |
| 307 _makeWriteAndReturn(Expression value) { |
| 308 var valueVariable = new VariableDeclaration.forValue(value); |
| 309 var dummy = new VariableDeclaration.forValue(new MethodInvocation( |
| 310 new ThisExpression(), |
| 311 _indexSet, |
| 312 new Arguments( |
| 313 <Expression>[indexAccess(), new VariableGet(valueVariable)]), |
| 314 setter)); |
| 315 return makeLet( |
| 316 valueVariable, makeLet(dummy, new VariableGet(valueVariable))); |
| 317 } |
| 318 |
| 319 Expression _finish(Expression body) => makeLet(indexVariable, body); |
| 320 } |
| 321 |
| 322 class SuperIndexAccessor extends Accessor { |
| 323 Expression index; |
| 324 VariableDeclaration indexVariable; |
| 325 Member getter, setter; |
| 326 |
| 327 SuperIndexAccessor(this.index, this.getter, this.setter); |
| 328 |
| 329 indexAccess() { |
| 330 indexVariable ??= new VariableDeclaration.forValue(index); |
| 331 return new VariableGet(indexVariable); |
| 332 } |
| 333 |
| 334 _makeSimpleRead() => new SuperMethodInvocation( |
| 335 _indexGet, new Arguments(<Expression>[index]), getter); |
| 336 |
| 337 _makeSimpleWrite(Expression value, bool voidContext) { |
| 338 if (!voidContext) return _makeWriteAndReturn(value); |
| 339 return new SuperMethodInvocation( |
| 340 _indexSet, new Arguments(<Expression>[index, value]), setter); |
| 341 } |
| 342 |
| 343 _makeRead() { |
| 344 return new SuperMethodInvocation( |
| 345 _indexGet, new Arguments(<Expression>[indexAccess()]), getter); |
| 346 } |
| 347 |
| 348 _makeWrite(Expression value, bool voidContext) { |
| 349 if (!voidContext) return _makeWriteAndReturn(value); |
| 350 return new SuperMethodInvocation( |
| 351 _indexSet, new Arguments(<Expression>[indexAccess(), value]), setter); |
| 352 } |
| 353 |
| 354 _makeWriteAndReturn(Expression value) { |
| 355 var valueVariable = new VariableDeclaration.forValue(value); |
| 356 var dummy = new VariableDeclaration.forValue(new SuperMethodInvocation( |
| 357 _indexSet, |
| 358 new Arguments( |
| 359 <Expression>[indexAccess(), new VariableGet(valueVariable)]), |
| 360 setter)); |
| 361 return makeLet( |
| 362 valueVariable, makeLet(dummy, new VariableGet(valueVariable))); |
| 363 } |
| 364 |
| 365 Expression _finish(Expression body) { |
| 366 return makeLet(indexVariable, body); |
| 367 } |
| 368 } |
| 369 |
| 370 class StaticAccessor extends Accessor { |
| 371 Member readTarget; |
| 372 Member writeTarget; |
| 373 |
| 374 StaticAccessor(this.readTarget, this.writeTarget); |
| 375 |
| 376 _makeRead() => |
| 377 readTarget == null ? makeInvalidRead() : new StaticGet(readTarget); |
| 378 |
| 379 _makeWrite(Expression value, bool voidContext) { |
| 380 return writeTarget == null |
| 381 ? makeInvalidWrite(value) |
| 382 : new StaticSet(writeTarget, value); |
| 383 } |
| 384 } |
| 385 |
| 386 class ReadOnlyAccessor extends Accessor { |
| 387 Expression expression; |
| 388 VariableDeclaration value; |
| 389 |
| 390 ReadOnlyAccessor(this.expression); |
| 391 |
| 392 _makeSimpleRead() => expression; |
| 393 |
| 394 _makeRead() { |
| 395 value ??= new VariableDeclaration.forValue(expression); |
| 396 return new VariableGet(value); |
| 397 } |
| 398 |
| 399 _makeWrite(Expression value, bool voidContext) => makeInvalidWrite(value); |
| 400 |
| 401 Expression _finish(Expression body) => makeLet(value, body); |
| 402 } |
| 403 |
| 404 Expression makeLet(VariableDeclaration variable, Expression body) { |
| 405 if (variable == null) return body; |
| 406 return new Let(variable, body); |
| 407 } |
| 408 |
| 409 Expression makeBinary(Expression left, Name operator, Procedure interfaceTarget, |
| 410 Expression right) { |
| 411 return new MethodInvocation( |
| 412 left, operator, new Arguments(<Expression>[right]), interfaceTarget); |
| 413 } |
| 414 |
| 415 final Name _equalOperator = new Name('=='); |
| 416 |
| 417 Expression buildIsNull(Expression value) { |
| 418 return makeBinary(value, _equalOperator, null, new NullLiteral()); |
| 419 } |
| 420 |
| 421 VariableDeclaration makeOrReuseVariable(Expression value) { |
| 422 // TODO: Devise a way to remember if a variable declaration was reused |
| 423 // or is fresh (hence needs a let binding). |
| 424 return new VariableDeclaration.forValue(value); |
| 425 } |
| 426 |
| 427 Expression wrapInvalid(Expression e) { |
| 428 return new Let(new VariableDeclaration.forValue(e), new InvalidExpression()); |
| 429 } |
OLD | NEW |