Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(38)

Side by Side Diff: pkg/front_end/lib/src/fasta/kernel/frontend_accessors.dart

Issue 2794013003: Re-duplicate frontend_accessors.dart. (Closed)
Patch Set: Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 }
OLDNEW
« no previous file with comments | « pkg/front_end/lib/src/fasta/kernel/fasta_accessors.dart ('k') | pkg/front_end/lib/src/fasta/names.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698