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