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, |
| 12 KernelConditionalExpression, |
11 KernelMethodInvocation, | 13 KernelMethodInvocation, |
12 KernelPropertyGet, | 14 KernelPropertyGet, |
13 KernelPropertySet, | 15 KernelPropertySet, |
| 16 KernelVariableDeclaration, |
14 KernelVariableGet, | 17 KernelVariableGet, |
15 KernelVariableSet; | 18 KernelVariableSet; |
16 | 19 |
17 import 'package:front_end/src/fasta/kernel/utils.dart' show offsetForToken; | 20 import 'package:front_end/src/fasta/kernel/utils.dart' show offsetForToken; |
18 | 21 |
19 import 'package:front_end/src/scanner/token.dart' show Token; | 22 import 'package:front_end/src/scanner/token.dart' show Token; |
20 | 23 |
21 import 'package:front_end/src/fasta/kernel/fasta_accessors.dart' | 24 import 'package:front_end/src/fasta/kernel/fasta_accessors.dart' |
22 show BuilderHelper; | 25 show BuilderHelper; |
23 | 26 |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
62 /// Returns an [Expression] representing a null-aware assignment (`??=`) with | 65 /// Returns an [Expression] representing a null-aware assignment (`??=`) with |
63 /// the accessor on the LHS and [value] on the RHS. | 66 /// the accessor on the LHS and [value] on the RHS. |
64 /// | 67 /// |
65 /// The returned expression evaluates to the assigned value, unless | 68 /// The returned expression evaluates to the assigned value, unless |
66 /// [voidContext] is true, in which case it may evaluate to anything. | 69 /// [voidContext] is true, in which case it may evaluate to anything. |
67 /// | 70 /// |
68 /// [type] is the static type of the RHS. | 71 /// [type] is the static type of the RHS. |
69 Expression buildNullAwareAssignment(Expression value, DartType type, | 72 Expression buildNullAwareAssignment(Expression value, DartType type, |
70 {bool voidContext: false}) { | 73 {bool voidContext: false}) { |
71 if (voidContext) { | 74 if (voidContext) { |
72 return _finish(new ConditionalExpression(buildIsNull(_makeRead()), | 75 return _finish(new KernelConditionalExpression( |
73 _makeWrite(value, false), new NullLiteral(), type)); | 76 buildIsNull(_makeRead()), _makeWrite(value, false), new NullLiteral(), |
| 77 isNullAwareCombiner: true)); |
74 } | 78 } |
75 var tmp = new VariableDeclaration.forValue(_makeRead()); | 79 var tmp = new VariableDeclaration.forValue(_makeRead()); |
76 return _finish(makeLet( | 80 return _finish(makeLet( |
77 tmp, | 81 tmp, |
78 new ConditionalExpression(buildIsNull(new VariableGet(tmp)), | 82 new KernelConditionalExpression(buildIsNull(new VariableGet(tmp)), |
79 _makeWrite(value, false), new VariableGet(tmp), type))); | 83 _makeWrite(value, false), new VariableGet(tmp), |
| 84 isNullAwareCombiner: true))); |
80 } | 85 } |
81 | 86 |
82 /// Returns an [Expression] representing a compound assignment (e.g. `+=`) | 87 /// Returns an [Expression] representing a compound assignment (e.g. `+=`) |
83 /// with the accessor on the LHS and [value] on the RHS. | 88 /// with the accessor on the LHS and [value] on the RHS. |
84 Expression buildCompoundAssignment(Name binaryOperator, Expression value, | 89 Expression buildCompoundAssignment(Name binaryOperator, Expression value, |
85 {int offset: TreeNode.noOffset, | 90 {int offset: TreeNode.noOffset, |
86 bool voidContext: false, | 91 bool voidContext: false, |
87 Procedure interfaceTarget}) { | 92 Procedure interfaceTarget}) { |
88 return _finish(_makeWrite( | 93 return _finish(_makeWrite( |
89 makeBinary(_makeRead(), binaryOperator, interfaceTarget, value, | 94 makeBinary(_makeRead(), binaryOperator, interfaceTarget, value, |
90 offset: offset), | 95 offset: offset, isCombiner: true), |
91 voidContext)); | 96 voidContext)); |
92 } | 97 } |
93 | 98 |
94 /// Returns an [Expression] representing a pre-increment or pre-decrement | 99 /// Returns an [Expression] representing a pre-increment or pre-decrement |
95 /// of the accessor. | 100 /// of the accessor. |
96 Expression buildPrefixIncrement(Name binaryOperator, | 101 Expression buildPrefixIncrement(Name binaryOperator, |
97 {int offset: TreeNode.noOffset, | 102 {int offset: TreeNode.noOffset, |
98 bool voidContext: false, | 103 bool voidContext: false, |
99 Procedure interfaceTarget}) { | 104 Procedure interfaceTarget}) { |
100 return buildCompoundAssignment(binaryOperator, new IntLiteral(1), | 105 return buildCompoundAssignment(binaryOperator, new IntLiteral(1), |
101 offset: offset, | 106 offset: offset, |
102 voidContext: voidContext, | 107 voidContext: voidContext, |
103 interfaceTarget: interfaceTarget); | 108 interfaceTarget: interfaceTarget); |
104 } | 109 } |
105 | 110 |
106 /// Returns an [Expression] representing a post-increment or post-decrement | 111 /// Returns an [Expression] representing a post-increment or post-decrement |
107 /// of the accessor. | 112 /// of the accessor. |
108 Expression buildPostfixIncrement(Name binaryOperator, | 113 Expression buildPostfixIncrement(Name binaryOperator, |
109 {int offset: TreeNode.noOffset, | 114 {int offset: TreeNode.noOffset, |
110 bool voidContext: false, | 115 bool voidContext: false, |
111 Procedure interfaceTarget}) { | 116 Procedure interfaceTarget}) { |
112 if (voidContext) { | 117 if (voidContext) { |
113 return buildPrefixIncrement(binaryOperator, | 118 return buildPrefixIncrement(binaryOperator, |
114 offset: offset, voidContext: true, interfaceTarget: interfaceTarget); | 119 offset: offset, voidContext: true, interfaceTarget: interfaceTarget); |
115 } | 120 } |
116 var value = new VariableDeclaration.forValue(_makeRead()); | 121 var value = new VariableDeclaration.forValue(_makeRead()); |
117 valueAccess() => new VariableGet(value); | 122 valueAccess() => new VariableGet(value); |
118 var dummy = new VariableDeclaration.forValue(_makeWrite( | 123 var dummy = new KernelVariableDeclaration.forValue( |
119 makeBinary( | 124 _makeWrite( |
120 valueAccess(), binaryOperator, interfaceTarget, new IntLiteral(1), | 125 makeBinary(valueAccess(), binaryOperator, interfaceTarget, |
121 offset: offset), | 126 new IntLiteral(1), |
122 true)); | 127 offset: offset, isCombiner: true), |
| 128 true), |
| 129 helper.functionNestingLevel, |
| 130 isDiscarding: true); |
123 return _finish(makeLet(value, makeLet(dummy, valueAccess()))); | 131 return _finish(makeLet(value, makeLet(dummy, valueAccess()))); |
124 } | 132 } |
125 | 133 |
126 Expression _makeSimpleRead() => _makeRead(); | 134 Expression _makeSimpleRead() => _makeRead(); |
127 | 135 |
128 Expression _makeSimpleWrite(Expression value, bool voidContext) { | 136 Expression _makeSimpleWrite(Expression value, bool voidContext) { |
129 return _makeWrite(value, voidContext); | 137 return _makeWrite(value, voidContext); |
130 } | 138 } |
131 | 139 |
132 Expression _makeRead(); | 140 Expression _makeRead(); |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
260 | 268 |
261 Expression _makeRead() => | 269 Expression _makeRead() => |
262 new KernelPropertyGet(receiverAccess(), name, getter); | 270 new KernelPropertyGet(receiverAccess(), name, getter); |
263 | 271 |
264 Expression _makeWrite(Expression value, bool voidContext) { | 272 Expression _makeWrite(Expression value, bool voidContext) { |
265 return new KernelPropertySet(receiverAccess(), name, value, setter); | 273 return new KernelPropertySet(receiverAccess(), name, value, setter); |
266 } | 274 } |
267 | 275 |
268 Expression _finish(Expression body) => makeLet( | 276 Expression _finish(Expression body) => makeLet( |
269 receiver, | 277 receiver, |
270 new ConditionalExpression( | 278 new KernelConditionalExpression( |
271 buildIsNull(receiverAccess()), new NullLiteral(), body, type)); | 279 buildIsNull(receiverAccess()), new NullLiteral(), body)); |
272 } | 280 } |
273 | 281 |
274 class SuperPropertyAccessor extends Accessor { | 282 class SuperPropertyAccessor extends Accessor { |
275 Name name; | 283 Name name; |
276 Member getter, setter; | 284 Member getter, setter; |
277 | 285 |
278 SuperPropertyAccessor( | 286 SuperPropertyAccessor( |
279 BuilderHelper helper, this.name, this.getter, this.setter, Token token) | 287 BuilderHelper helper, this.name, this.getter, this.setter, Token token) |
280 : super(helper, token); | 288 : super(helper, token); |
281 | 289 |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
356 interfaceTarget: setter) | 364 interfaceTarget: setter) |
357 ..fileOffset = offsetForToken(token); | 365 ..fileOffset = offsetForToken(token); |
358 } | 366 } |
359 | 367 |
360 // TODO(dmitryas): remove this method after the "[]=" operator of the Context | 368 // TODO(dmitryas): remove this method after the "[]=" operator of the Context |
361 // class is made to return a value. | 369 // class is made to return a value. |
362 _makeWriteAndReturn(Expression value) { | 370 _makeWriteAndReturn(Expression value) { |
363 // The call to []= does not return the value like direct-style assignments | 371 // The call to []= does not return the value like direct-style assignments |
364 // do. We need to bind the value in a let. | 372 // do. We need to bind the value in a let. |
365 var valueVariable = new VariableDeclaration.forValue(value); | 373 var valueVariable = new VariableDeclaration.forValue(value); |
366 var dummy = new VariableDeclaration.forValue(new KernelMethodInvocation( | 374 var dummy = new KernelVariableDeclaration.forValue( |
367 receiverAccess(), | 375 new KernelMethodInvocation( |
368 indexSetName, | 376 receiverAccess(), |
369 new KernelArguments( | 377 indexSetName, |
370 <Expression>[indexAccess(), new VariableGet(valueVariable)]), | 378 new KernelArguments( |
371 interfaceTarget: setter) | 379 <Expression>[indexAccess(), new VariableGet(valueVariable)]), |
372 ..fileOffset = offsetForToken(token)); | 380 interfaceTarget: setter) |
| 381 ..fileOffset = offsetForToken(token), |
| 382 helper.functionNestingLevel, |
| 383 isDiscarding: true); |
373 return makeLet( | 384 return makeLet( |
374 valueVariable, makeLet(dummy, new VariableGet(valueVariable))); | 385 valueVariable, makeLet(dummy, new VariableGet(valueVariable))); |
375 } | 386 } |
376 | 387 |
377 Expression _finish(Expression body) { | 388 Expression _finish(Expression body) { |
378 return makeLet(receiverVariable, makeLet(indexVariable, body)); | 389 if (receiverVariable == null) { |
| 390 assert(indexVariable == null); |
| 391 return body; |
| 392 } else { |
| 393 return new KernelComplexAssign( |
| 394 receiverVariable, makeLet(indexVariable, body)); |
| 395 } |
379 } | 396 } |
380 } | 397 } |
381 | 398 |
382 /// Special case of [IndexAccessor] to avoid creating an indirect access to | 399 /// Special case of [IndexAccessor] to avoid creating an indirect access to |
383 /// 'this'. | 400 /// 'this'. |
384 class ThisIndexAccessor extends Accessor { | 401 class ThisIndexAccessor extends Accessor { |
385 Expression index; | 402 Expression index; |
386 VariableDeclaration indexVariable; | 403 VariableDeclaration indexVariable; |
387 Procedure getter, setter; | 404 Procedure getter, setter; |
388 | 405 |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
524 Expression _finish(Expression body) => makeLet(value, body); | 541 Expression _finish(Expression body) => makeLet(value, body); |
525 } | 542 } |
526 | 543 |
527 Expression makeLet(VariableDeclaration variable, Expression body) { | 544 Expression makeLet(VariableDeclaration variable, Expression body) { |
528 if (variable == null) return body; | 545 if (variable == null) return body; |
529 return new Let(variable, body); | 546 return new Let(variable, body); |
530 } | 547 } |
531 | 548 |
532 Expression makeBinary( | 549 Expression makeBinary( |
533 Expression left, Name operator, Procedure interfaceTarget, Expression right, | 550 Expression left, Name operator, Procedure interfaceTarget, Expression right, |
534 {int offset: TreeNode.noOffset}) { | 551 {int offset: TreeNode.noOffset, bool isCombiner: false}) { |
535 return new KernelMethodInvocation( | 552 return new KernelMethodInvocation( |
536 left, operator, new KernelArguments(<Expression>[right]), | 553 left, operator, new KernelArguments(<Expression>[right]), |
537 interfaceTarget: interfaceTarget) | 554 interfaceTarget: interfaceTarget, isCombiner: isCombiner) |
538 ..fileOffset = offset; | 555 ..fileOffset = offset; |
539 } | 556 } |
540 | 557 |
541 Expression buildIsNull(Expression value, {int offset: TreeNode.noOffset}) { | 558 Expression buildIsNull(Expression value, {int offset: TreeNode.noOffset}) { |
542 return makeBinary(value, equalsName, null, new NullLiteral(), offset: offset); | 559 return makeBinary(value, equalsName, null, new NullLiteral(), offset: offset); |
543 } | 560 } |
544 | 561 |
545 VariableDeclaration makeOrReuseVariable(Expression value) { | 562 VariableDeclaration makeOrReuseVariable(Expression value) { |
546 // TODO: Devise a way to remember if a variable declaration was reused | 563 // TODO: Devise a way to remember if a variable declaration was reused |
547 // or is fresh (hence needs a let binding). | 564 // or is fresh (hence needs a let binding). |
548 return new VariableDeclaration.forValue(value); | 565 return new VariableDeclaration.forValue(value); |
549 } | 566 } |
OLD | NEW |