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 library fasta.builder_accessors; | |
6 | |
7 export 'package:kernel/frontend/accessors.dart' show wrapInvalid; | |
8 | |
9 import 'package:kernel/frontend/accessors.dart' | |
10 show Accessor, buildIsNull, makeLet; | |
11 | |
12 import 'package:kernel/ast.dart'; | |
13 | |
14 import '../errors.dart' show internalError; | |
15 | |
16 import '../builder/scope.dart' show AccessErrorBuilder, ProblemBuilder; | |
17 | |
18 import 'package:kernel/frontend/accessors.dart' as kernel | |
19 show | |
20 IndexAccessor, | |
21 NullAwarePropertyAccessor, | |
22 PropertyAccessor, | |
23 StaticAccessor, | |
24 SuperIndexAccessor, | |
25 SuperPropertyAccessor, | |
26 ThisIndexAccessor, | |
27 ThisPropertyAccessor, | |
28 VariableAccessor; | |
29 | |
30 import 'kernel_builder.dart' | |
31 show Builder, KernelClassBuilder, PrefixBuilder, TypeDeclarationBuilder; | |
32 | |
33 import '../names.dart' show callName; | |
34 | |
35 abstract class BuilderHelper { | |
36 Uri get uri; | |
37 | |
38 Constructor lookupConstructor(Name name, {bool isSuper}); | |
39 | |
40 Expression toSuperMethodInvocation(MethodInvocation node); | |
41 | |
42 Expression toValue(node); | |
43 | |
44 Member lookupSuperMember(Name name, {bool isSetter: false}); | |
45 | |
46 builderToFirstExpression(Builder builder, String name, int offset); | |
47 | |
48 finishSend(Object receiver, Arguments arguments, int offset); | |
49 | |
50 Expression buildCompileTimeError(error, [int offset]); | |
51 | |
52 Initializer buildCompileTimeErrorIntializer(error, [int offset]); | |
53 | |
54 Expression buildStaticInvocation(Procedure target, Arguments arguments); | |
55 | |
56 Expression buildProblemExpression(ProblemBuilder builder, int offset); | |
57 | |
58 Expression throwNoSuchMethodError( | |
59 String name, Arguments arguments, int offset, | |
60 {bool isSuper: false, isGetter: false, isSetter: false}); | |
61 } | |
62 | |
63 abstract class BuilderAccessor implements Accessor { | |
64 BuilderHelper get helper; | |
65 | |
66 String get plainNameForRead; | |
67 | |
68 Uri get uri => helper.uri; | |
69 | |
70 String get plainNameForWrite => plainNameForRead; | |
71 | |
72 Expression buildForEffect() => buildSimpleRead(); | |
73 | |
74 Initializer buildFieldInitializer( | |
75 Map<String, FieldInitializer> initializers) { | |
76 // TODO(ahe): This error message is really bad. | |
77 return helper.buildCompileTimeErrorIntializer( | |
78 "Can't use $plainNameForRead here.", offset); | |
79 } | |
80 | |
81 Expression makeInvalidRead() { | |
82 return buildThrowNoSuchMethodError(new Arguments.empty(), isGetter: true); | |
83 } | |
84 | |
85 Expression makeInvalidWrite(Expression value) { | |
86 return buildThrowNoSuchMethodError(new Arguments(<Expression>[value]), | |
87 isSetter: true); | |
88 } | |
89 | |
90 /* Expression | BuilderAccessor */ doInvocation( | |
91 int offset, Arguments arguments); | |
92 | |
93 /* Expression | BuilderAccessor */ buildPropertyAccess( | |
94 IncompleteSend send, bool isNullAware) { | |
95 if (send is SendAccessor) { | |
96 return buildMethodInvocation( | |
97 buildSimpleRead(), send.name, send.arguments, send.offset, | |
98 isNullAware: isNullAware); | |
99 } else { | |
100 return PropertyAccessor.make(helper, send.offset, buildSimpleRead(), | |
101 send.name, null, null, isNullAware); | |
102 } | |
103 } | |
104 | |
105 /* Expression | BuilderAccessor */ buildThrowNoSuchMethodError( | |
106 Arguments arguments, | |
107 {bool isSuper: false, | |
108 isGetter: false, | |
109 isSetter: false, | |
110 String name, | |
111 int offset}) { | |
112 return helper.throwNoSuchMethodError( | |
113 name ?? plainNameForWrite, arguments, offset ?? this.offset, | |
114 isGetter: isGetter, isSetter: isSetter, isSuper: isSuper); | |
115 } | |
116 | |
117 bool get isThisPropertyAccessor => false; | |
118 } | |
119 | |
120 abstract class CompileTimeErrorAccessor implements BuilderAccessor { | |
121 @override | |
122 Expression get builtBinary => internalError("Unsupported operation."); | |
123 | |
124 @override | |
125 void set builtBinary(Expression expression) { | |
126 internalError("Unsupported operation."); | |
127 } | |
128 | |
129 @override | |
130 Expression get builtGetter => internalError("Unsupported operation."); | |
131 | |
132 @override | |
133 void set builtGetter(Expression expression) { | |
134 internalError("Unsupported operation."); | |
135 } | |
136 | |
137 Expression buildError(); | |
138 | |
139 Name get name => internalError("Unsupported operation."); | |
140 | |
141 String get plainNameForRead => name.name; | |
142 | |
143 withReceiver(Object receiver, {bool isNullAware}) => this; | |
144 | |
145 Initializer buildFieldInitializer( | |
146 Map<String, FieldInitializer> initializers) { | |
147 return new LocalInitializer(new VariableDeclaration.forValue(buildError())); | |
148 } | |
149 | |
150 doInvocation(int offset, Arguments arguments) => this; | |
151 | |
152 buildPropertyAccess(IncompleteSend send, bool isNullAware) => this; | |
153 | |
154 buildThrowNoSuchMethodError(Arguments arguments, | |
155 {bool isSuper: false, | |
156 isGetter: false, | |
157 isSetter: false, | |
158 String name, | |
159 int offset}) { | |
160 return this; | |
161 } | |
162 | |
163 Expression buildAssignment(Expression value, {bool voidContext: false}) { | |
164 return buildError(); | |
165 } | |
166 | |
167 Expression buildCompoundAssignment(Name binaryOperator, Expression value, | |
168 {int offset: TreeNode.noOffset, | |
169 bool voidContext: false, | |
170 Procedure interfaceTarget}) { | |
171 return buildError(); | |
172 } | |
173 | |
174 Expression buildPrefixIncrement(Name binaryOperator, | |
175 {int offset: TreeNode.noOffset, | |
176 bool voidContext: false, | |
177 Procedure interfaceTarget}) { | |
178 return buildError(); | |
179 } | |
180 | |
181 Expression buildPostfixIncrement(Name binaryOperator, | |
182 {int offset: TreeNode.noOffset, | |
183 bool voidContext: false, | |
184 Procedure interfaceTarget}) { | |
185 return buildError(); | |
186 } | |
187 | |
188 Expression buildNullAwareAssignment(Expression value, DartType type, | |
189 {bool voidContext: false}) { | |
190 return buildError(); | |
191 } | |
192 | |
193 Expression buildSimpleRead() => buildError(); | |
194 | |
195 Expression makeInvalidRead() => buildError(); | |
196 | |
197 Expression makeInvalidWrite(Expression value) => buildError(); | |
198 } | |
199 | |
200 class ThisAccessor extends BuilderAccessor { | |
201 final BuilderHelper helper; | |
202 | |
203 final int offset; | |
204 | |
205 final bool isInitializer; | |
206 | |
207 final bool isSuper; | |
208 | |
209 ThisAccessor(this.helper, this.offset, this.isInitializer, | |
210 {this.isSuper: false}); | |
211 | |
212 @override | |
213 Expression get builtBinary => internalError("Unsupported operation."); | |
214 | |
215 @override | |
216 void set builtBinary(Expression expression) { | |
217 internalError("Unsupported operation."); | |
218 } | |
219 | |
220 @override | |
221 Expression get builtGetter => internalError("Unsupported operation."); | |
222 | |
223 @override | |
224 void set builtGetter(Expression expression) { | |
225 internalError("Unsupported operation."); | |
226 } | |
227 | |
228 String get plainNameForRead => internalError(isSuper ? "super" : "this"); | |
229 | |
230 Expression buildSimpleRead() { | |
231 if (!isSuper) { | |
232 return new ThisExpression(); | |
233 } else { | |
234 return helper.buildCompileTimeError( | |
235 "Can't use `super` as an expression.", offset); | |
236 } | |
237 } | |
238 | |
239 Initializer buildFieldInitializer( | |
240 Map<String, FieldInitializer> initializers) { | |
241 String keyword = isSuper ? "super" : "this"; | |
242 return helper.buildCompileTimeErrorIntializer( | |
243 "Can't use '$keyword' here, did you mean '$keyword()'?", offset); | |
244 } | |
245 | |
246 buildPropertyAccess(IncompleteSend send, bool isNullAware) { | |
247 if (isInitializer && send is SendAccessor) { | |
248 return buildConstructorInitializer( | |
249 send.offset, send.name, send.arguments); | |
250 } | |
251 if (send is SendAccessor) { | |
252 // Notice that 'this' or 'super' can't be null. So we can ignore the | |
253 // value of [isNullAware]. | |
254 MethodInvocation result = buildMethodInvocation( | |
255 new ThisExpression(), send.name, send.arguments, offset); | |
256 return isSuper ? helper.toSuperMethodInvocation(result) : result; | |
257 } else { | |
258 if (isSuper) { | |
259 Member getter = helper.lookupSuperMember(send.name); | |
260 Member setter = helper.lookupSuperMember(send.name, isSetter: true); | |
261 return new SuperPropertyAccessor( | |
262 helper, send.offset, send.name, getter, setter); | |
263 } else { | |
264 return new ThisPropertyAccessor( | |
265 helper, send.offset, send.name, null, null); | |
266 } | |
267 } | |
268 } | |
269 | |
270 doInvocation(int offset, Arguments arguments) { | |
271 if (isInitializer) { | |
272 return buildConstructorInitializer(offset, new Name(""), arguments); | |
273 } else { | |
274 return buildMethodInvocation( | |
275 new ThisExpression(), callName, arguments, offset); | |
276 } | |
277 } | |
278 | |
279 Initializer buildConstructorInitializer( | |
280 int offset, Name name, Arguments arguments) { | |
281 Constructor constructor = helper.lookupConstructor(name, isSuper: isSuper); | |
282 Initializer result; | |
283 if (constructor == null) { | |
284 result = new LocalInitializer(new VariableDeclaration.forValue( | |
285 buildThrowNoSuchMethodError(arguments, | |
286 isSuper: isSuper, name: name.name, offset: offset))); | |
287 } else if (isSuper) { | |
288 result = new SuperInitializer(constructor, arguments); | |
289 } else { | |
290 result = new RedirectingInitializer(constructor, arguments); | |
291 } | |
292 return result..fileOffset = offset; | |
293 } | |
294 | |
295 Expression buildAssignment(Expression value, {bool voidContext: false}) { | |
296 return buildAssignmentError(); | |
297 } | |
298 | |
299 Expression buildNullAwareAssignment(Expression value, DartType type, | |
300 {bool voidContext: false}) { | |
301 return buildAssignmentError(); | |
302 } | |
303 | |
304 Expression buildCompoundAssignment(Name binaryOperator, Expression value, | |
305 {int offset: TreeNode.noOffset, | |
306 bool voidContext: false, | |
307 Procedure interfaceTarget}) { | |
308 return buildAssignmentError(); | |
309 } | |
310 | |
311 Expression buildPrefixIncrement(Name binaryOperator, | |
312 {int offset: TreeNode.noOffset, | |
313 bool voidContext: false, | |
314 Procedure interfaceTarget}) { | |
315 return buildAssignmentError(); | |
316 } | |
317 | |
318 Expression buildPostfixIncrement(Name binaryOperator, | |
319 {int offset: TreeNode.noOffset, | |
320 bool voidContext: false, | |
321 Procedure interfaceTarget}) { | |
322 return buildAssignmentError(); | |
323 } | |
324 | |
325 Expression buildAssignmentError() { | |
326 String message = | |
327 isSuper ? "Can't assign to 'super'." : "Can't assign to 'this'."; | |
328 return helper.buildCompileTimeError(message, offset); | |
329 } | |
330 | |
331 toString() => "ThisAccessor($offset${isSuper ? ', super' : ''})"; | |
332 } | |
333 | |
334 abstract class IncompleteSend extends BuilderAccessor { | |
335 final BuilderHelper helper; | |
336 | |
337 @override | |
338 final int offset; | |
339 | |
340 final Name name; | |
341 | |
342 IncompleteSend(this.helper, this.offset, this.name); | |
343 | |
344 @override | |
345 Expression get builtBinary => internalError("Unsupported operation."); | |
346 | |
347 @override | |
348 void set builtBinary(Expression expression) { | |
349 internalError("Unsupported operation."); | |
350 } | |
351 | |
352 @override | |
353 Expression get builtGetter => internalError("Unsupported operation."); | |
354 | |
355 @override | |
356 void set builtGetter(Expression expression) { | |
357 internalError("Unsupported operation."); | |
358 } | |
359 | |
360 withReceiver(Object receiver, {bool isNullAware}); | |
361 } | |
362 | |
363 class IncompleteError extends IncompleteSend with CompileTimeErrorAccessor { | |
364 final Object error; | |
365 | |
366 IncompleteError(BuilderHelper helper, int offset, this.error) | |
367 : super(helper, offset, null); | |
368 | |
369 Expression buildError() { | |
370 return helper.buildCompileTimeError(error, offset); | |
371 } | |
372 } | |
373 | |
374 class SendAccessor extends IncompleteSend { | |
375 final Arguments arguments; | |
376 | |
377 SendAccessor(BuilderHelper helper, int offset, Name name, this.arguments) | |
378 : super(helper, offset, name) { | |
379 assert(arguments != null); | |
380 } | |
381 | |
382 String get plainNameForRead => name.name; | |
383 | |
384 Expression buildSimpleRead() { | |
385 return internalError("Unhandled"); | |
386 } | |
387 | |
388 Expression buildAssignment(Expression value, {bool voidContext: false}) { | |
389 return internalError("Unhandled"); | |
390 } | |
391 | |
392 withReceiver(Object receiver, {bool isNullAware: false}) { | |
393 if (receiver is TypeDeclarationBuilder) { | |
394 /// `SomeType?.toString` is the same as `SomeType.toString`, not | |
395 /// `(SomeType).toString`. | |
396 isNullAware = false; | |
397 } | |
398 if (receiver is BuilderAccessor) { | |
399 return receiver.buildPropertyAccess(this, isNullAware); | |
400 } | |
401 if (receiver is PrefixBuilder) { | |
402 PrefixBuilder prefix = receiver; | |
403 receiver = helper.builderToFirstExpression( | |
404 prefix.exports[name.name], "${prefix.name}.${name.name}", offset); | |
405 return helper.finishSend(receiver, arguments, offset); | |
406 } | |
407 Expression result; | |
408 if (receiver is KernelClassBuilder) { | |
409 Builder builder = receiver.findStaticBuilder(name.name, offset, uri); | |
410 if (builder == null) { | |
411 return buildThrowNoSuchMethodError(arguments); | |
412 } | |
413 if (builder.hasProblem) { | |
414 result = helper.buildProblemExpression(builder, offset); | |
415 } else { | |
416 Member target = builder.target; | |
417 if (target != null) { | |
418 if (target is Field) { | |
419 result = buildMethodInvocation(new StaticGet(target), callName, | |
420 arguments, offset + (target.name?.name?.length ?? 0), | |
421 isNullAware: isNullAware); | |
422 } else { | |
423 result = helper.buildStaticInvocation(target, arguments) | |
424 ..fileOffset = offset; | |
425 } | |
426 } else { | |
427 result = buildThrowNoSuchMethodError(arguments)..fileOffset = offset; | |
428 } | |
429 } | |
430 } else { | |
431 result = buildMethodInvocation( | |
432 helper.toValue(receiver), name, arguments, offset, | |
433 isNullAware: isNullAware); | |
434 } | |
435 return result; | |
436 } | |
437 | |
438 Expression buildNullAwareAssignment(Expression value, DartType type, | |
439 {bool voidContext: false}) { | |
440 return internalError("Unhandled"); | |
441 } | |
442 | |
443 Expression buildCompoundAssignment(Name binaryOperator, Expression value, | |
444 {int offset, bool voidContext: false, Procedure interfaceTarget}) { | |
445 return internalError("Unhandled"); | |
446 } | |
447 | |
448 Expression buildPrefixIncrement(Name binaryOperator, | |
449 {int offset, bool voidContext: false, Procedure interfaceTarget}) { | |
450 return internalError("Unhandled"); | |
451 } | |
452 | |
453 Expression buildPostfixIncrement(Name binaryOperator, | |
454 {int offset, bool voidContext: false, Procedure interfaceTarget}) { | |
455 return internalError("Unhandled"); | |
456 } | |
457 | |
458 Expression doInvocation(int offset, Arguments arguments) { | |
459 return internalError("Unhandled"); | |
460 } | |
461 | |
462 toString() => "SendAccessor($offset, $name, $arguments)"; | |
463 } | |
464 | |
465 class IncompletePropertyAccessor extends IncompleteSend { | |
466 IncompletePropertyAccessor(BuilderHelper helper, int offset, Name name) | |
467 : super(helper, offset, name); | |
468 | |
469 String get plainNameForRead => name.name; | |
470 | |
471 Expression buildSimpleRead() => internalError("Unhandled"); | |
472 | |
473 Expression buildAssignment(Expression value, {bool voidContext: false}) { | |
474 return internalError("Unhandled"); | |
475 } | |
476 | |
477 withReceiver(Object receiver, {bool isNullAware: false}) { | |
478 if (receiver is TypeDeclarationBuilder) { | |
479 /// For reasons beyond comprehension, `SomeType?.toString` is the same as | |
480 /// `SomeType.toString`, not `(SomeType).toString`. WTAF!?! | |
481 // | |
482 isNullAware = false; | |
483 } | |
484 if (receiver is BuilderAccessor) { | |
485 return receiver.buildPropertyAccess(this, isNullAware); | |
486 } | |
487 if (receiver is PrefixBuilder) { | |
488 PrefixBuilder prefix = receiver; | |
489 return helper.builderToFirstExpression( | |
490 prefix.exports[name.name], name.name, offset); | |
491 } | |
492 if (receiver is KernelClassBuilder) { | |
493 Builder builder = receiver.findStaticBuilder(name.name, offset, uri); | |
494 if (builder == null) { | |
495 // If we find a setter, [builder] is an [AccessErrorBuilder], not null. | |
496 return buildThrowNoSuchMethodError(new Arguments.empty(), | |
497 isGetter: true); | |
498 } | |
499 Builder setter; | |
500 if (builder.isSetter) { | |
501 setter = builder; | |
502 } else if (builder.isGetter) { | |
503 setter = | |
504 receiver.findStaticBuilder(name.name, offset, uri, isSetter: true); | |
505 } else if (builder.isField && !builder.isFinal) { | |
506 setter = builder; | |
507 } | |
508 return new StaticAccessor.fromBuilder(helper, builder, offset, setter); | |
509 } | |
510 return PropertyAccessor.make(helper, offset, helper.toValue(receiver), name, | |
511 null, null, isNullAware); | |
512 } | |
513 | |
514 Expression buildNullAwareAssignment(Expression value, DartType type, | |
515 {bool voidContext: false}) { | |
516 return internalError("Unhandled"); | |
517 } | |
518 | |
519 Expression buildCompoundAssignment(Name binaryOperator, Expression value, | |
520 {int offset, bool voidContext: false, Procedure interfaceTarget}) { | |
521 return internalError("Unhandled"); | |
522 } | |
523 | |
524 Expression buildPrefixIncrement(Name binaryOperator, | |
525 {int offset, bool voidContext: false, Procedure interfaceTarget}) { | |
526 return internalError("Unhandled"); | |
527 } | |
528 | |
529 Expression buildPostfixIncrement(Name binaryOperator, | |
530 {int offset, bool voidContext: false, Procedure interfaceTarget}) { | |
531 return internalError("Unhandled"); | |
532 } | |
533 | |
534 Expression doInvocation(int offset, Arguments arguments) { | |
535 return internalError("Unhandled"); | |
536 } | |
537 | |
538 toString() => "IncompletePropertyAccessor($offset, $name)"; | |
539 } | |
540 | |
541 class IndexAccessor extends kernel.IndexAccessor with BuilderAccessor { | |
542 final BuilderHelper helper; | |
543 | |
544 IndexAccessor.internal(this.helper, int offset, Expression receiver, | |
545 Expression index, Procedure getter, Procedure setter) | |
546 : super.internal(receiver, index, getter, setter, offset); | |
547 | |
548 String get plainNameForRead => "[]"; | |
549 | |
550 String get plainNameForWrite => "[]="; | |
551 | |
552 Expression doInvocation(int offset, Arguments arguments) { | |
553 return buildMethodInvocation( | |
554 buildSimpleRead(), callName, arguments, offset); | |
555 } | |
556 | |
557 toString() => "IndexAccessor()"; | |
558 | |
559 static BuilderAccessor make( | |
560 BuilderHelper helper, | |
561 int offset, | |
562 Expression receiver, | |
563 Expression index, | |
564 Procedure getter, | |
565 Procedure setter) { | |
566 if (receiver is ThisExpression) { | |
567 return new ThisIndexAccessor(helper, offset, index, getter, setter); | |
568 } else { | |
569 return new IndexAccessor.internal( | |
570 helper, offset, receiver, index, getter, setter); | |
571 } | |
572 } | |
573 } | |
574 | |
575 class PropertyAccessor extends kernel.PropertyAccessor with BuilderAccessor { | |
576 final BuilderHelper helper; | |
577 | |
578 PropertyAccessor.internal(this.helper, int offset, Expression receiver, | |
579 Name name, Member getter, Member setter) | |
580 : super.internal(receiver, name, getter, setter, offset); | |
581 | |
582 String get plainNameForRead => name.name; | |
583 | |
584 bool get isThisPropertyAccessor => receiver is ThisExpression; | |
585 | |
586 Expression doInvocation(int offset, Arguments arguments) { | |
587 return buildMethodInvocation(receiver, name, arguments, offset); | |
588 } | |
589 | |
590 toString() => "PropertyAccessor()"; | |
591 | |
592 static BuilderAccessor make( | |
593 BuilderHelper helper, | |
594 int offset, | |
595 Expression receiver, | |
596 Name name, | |
597 Member getter, | |
598 Member setter, | |
599 bool isNullAware) { | |
600 if (receiver is ThisExpression) { | |
601 return new ThisPropertyAccessor(helper, offset, name, getter, setter); | |
602 } else { | |
603 return isNullAware | |
604 ? new NullAwarePropertyAccessor( | |
605 helper, offset, receiver, name, getter, setter, null) | |
606 : new PropertyAccessor.internal( | |
607 helper, offset, receiver, name, getter, setter); | |
608 } | |
609 } | |
610 } | |
611 | |
612 class StaticAccessor extends kernel.StaticAccessor with BuilderAccessor { | |
613 final BuilderHelper helper; | |
614 | |
615 StaticAccessor(this.helper, int offset, Member readTarget, Member writeTarget) | |
616 : super(readTarget, writeTarget, offset) { | |
617 assert(readTarget != null || writeTarget != null); | |
618 } | |
619 | |
620 factory StaticAccessor.fromBuilder(BuilderHelper helper, Builder builder, | |
621 int offset, Builder builderSetter) { | |
622 if (builder is AccessErrorBuilder) { | |
623 AccessErrorBuilder error = builder; | |
624 builder = error.builder; | |
625 // We should only see an access error here if we've looked up a setter | |
626 // when not explicitly looking for a setter. | |
627 assert(builder.isSetter); | |
628 } else if (builder.target == null) { | |
629 return internalError("Unhandled: ${builder}"); | |
630 } | |
631 Member getter = builder.target.hasGetter ? builder.target : null; | |
632 Member setter = builder.target.hasSetter ? builder.target : null; | |
633 if (setter == null) { | |
634 if (builderSetter?.target?.hasSetter ?? false) { | |
635 setter = builderSetter.target; | |
636 } | |
637 } | |
638 return new StaticAccessor(helper, offset, getter, setter); | |
639 } | |
640 | |
641 String get plainNameForRead => (readTarget ?? writeTarget).name.name; | |
642 | |
643 Expression doInvocation(int offset, Arguments arguments) { | |
644 if (readTarget == null || isFieldOrGetter(readTarget)) { | |
645 return buildMethodInvocation(buildSimpleRead(), callName, arguments, | |
646 offset + (readTarget?.name?.name?.length ?? 0)); | |
647 } else { | |
648 return helper.buildStaticInvocation(readTarget, arguments) | |
649 ..fileOffset = offset; | |
650 } | |
651 } | |
652 | |
653 toString() => "StaticAccessor()"; | |
654 } | |
655 | |
656 class SuperPropertyAccessor extends kernel.SuperPropertyAccessor | |
657 with BuilderAccessor { | |
658 final BuilderHelper helper; | |
659 | |
660 SuperPropertyAccessor( | |
661 this.helper, int offset, Name name, Member getter, Member setter) | |
662 : super(name, getter, setter, offset); | |
663 | |
664 String get plainNameForRead => name.name; | |
665 | |
666 Expression doInvocation(int offset, Arguments arguments) { | |
667 if (getter == null || isFieldOrGetter(getter)) { | |
668 return buildMethodInvocation( | |
669 buildSimpleRead(), callName, arguments, offset); | |
670 } else { | |
671 return new DirectMethodInvocation(new ThisExpression(), getter, arguments) | |
672 ..fileOffset = offset; | |
673 } | |
674 } | |
675 | |
676 toString() => "SuperPropertyAccessor()"; | |
677 } | |
678 | |
679 class ThisIndexAccessor extends kernel.ThisIndexAccessor with BuilderAccessor { | |
680 final BuilderHelper helper; | |
681 | |
682 ThisIndexAccessor(this.helper, int offset, Expression index, Procedure getter, | |
683 Procedure setter) | |
684 : super(index, getter, setter, offset); | |
685 | |
686 String get plainNameForRead => "[]"; | |
687 | |
688 String get plainNameForWrite => "[]="; | |
689 | |
690 Expression doInvocation(int offset, Arguments arguments) { | |
691 return buildMethodInvocation( | |
692 buildSimpleRead(), callName, arguments, offset); | |
693 } | |
694 | |
695 toString() => "ThisIndexAccessor()"; | |
696 } | |
697 | |
698 class SuperIndexAccessor extends kernel.SuperIndexAccessor | |
699 with BuilderAccessor { | |
700 final BuilderHelper helper; | |
701 | |
702 SuperIndexAccessor( | |
703 this.helper, int offset, Expression index, Member getter, Member setter) | |
704 : super(index, getter, setter, offset); | |
705 | |
706 String get plainNameForRead => "[]"; | |
707 | |
708 String get plainNameForWrite => "[]="; | |
709 | |
710 Expression doInvocation(int offset, Arguments arguments) { | |
711 return buildMethodInvocation( | |
712 buildSimpleRead(), callName, arguments, offset); | |
713 } | |
714 | |
715 toString() => "SuperIndexAccessor()"; | |
716 } | |
717 | |
718 class ThisPropertyAccessor extends kernel.ThisPropertyAccessor | |
719 with BuilderAccessor { | |
720 final BuilderHelper helper; | |
721 | |
722 ThisPropertyAccessor( | |
723 this.helper, int offset, Name name, Member getter, Member setter) | |
724 : super(name, getter, setter, offset); | |
725 | |
726 String get plainNameForRead => name.name; | |
727 | |
728 bool get isThisPropertyAccessor => true; | |
729 | |
730 Expression doInvocation(int offset, Arguments arguments) { | |
731 Member interfaceTarget = getter; | |
732 if (interfaceTarget is Field) { | |
733 // TODO(ahe): In strong mode we should probably rewrite this to | |
734 // `this.name.call(arguments)`. | |
735 interfaceTarget = null; | |
736 } | |
737 return buildMethodInvocation(new ThisExpression(), name, arguments, offset); | |
738 } | |
739 | |
740 toString() => "ThisPropertyAccessor()"; | |
741 } | |
742 | |
743 class NullAwarePropertyAccessor extends kernel.NullAwarePropertyAccessor | |
744 with BuilderAccessor { | |
745 final BuilderHelper helper; | |
746 | |
747 NullAwarePropertyAccessor(this.helper, int offset, Expression receiver, | |
748 Name name, Member getter, Member setter, DartType type) | |
749 : super(receiver, name, getter, setter, type, offset); | |
750 | |
751 String get plainNameForRead => name.name; | |
752 | |
753 Expression doInvocation(int offset, Arguments arguments) { | |
754 return internalError("Not implemented yet."); | |
755 } | |
756 | |
757 toString() => "NullAwarePropertyAccessor()"; | |
758 } | |
759 | |
760 class VariableAccessor extends kernel.VariableAccessor with BuilderAccessor { | |
761 final BuilderHelper helper; | |
762 | |
763 VariableAccessor(this.helper, int offset, VariableDeclaration variable, | |
764 [DartType promotedType]) | |
765 : super(variable, promotedType, offset); | |
766 | |
767 String get plainNameForRead => variable.name; | |
768 | |
769 Expression doInvocation(int offset, Arguments arguments) { | |
770 // Normally the offset is at the start of the token, but in this case, | |
771 // because we insert a '.call', we want it at the end instead. | |
772 return buildMethodInvocation(buildSimpleRead(), callName, arguments, | |
773 offset + (variable.name?.length ?? 0)); | |
774 } | |
775 | |
776 toString() => "VariableAccessor()"; | |
777 } | |
778 | |
779 bool isFieldOrGetter(Member member) { | |
780 return member is Field || (member is Procedure && member.isGetter); | |
781 } | |
782 | |
783 Expression buildMethodInvocation( | |
784 Expression receiver, Name name, Arguments arguments, int offset, | |
785 {bool isNullAware: false}) { | |
786 if (isNullAware) { | |
787 VariableDeclaration variable = new VariableDeclaration.forValue(receiver); | |
788 return makeLet( | |
789 variable, | |
790 new ConditionalExpression( | |
791 buildIsNull(new VariableGet(variable)), | |
792 new NullLiteral(), | |
793 new MethodInvocation(new VariableGet(variable), name, arguments) | |
794 ..fileOffset = offset, | |
795 const DynamicType())); | |
796 } else { | |
797 return new MethodInvocation(receiver, name, arguments)..fileOffset = offset; | |
798 } | |
799 } | |
OLD | NEW |