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

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

Issue 2628043005: Fasta kernel AST builder. (Closed)
Patch Set: Address review comments. Created 3 years, 11 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
« no previous file with comments | « no previous file | pkg/fasta/lib/src/kernel/builder_accessors.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 library fasta.body_builder;
6
7 import 'package:dart_parser/src/parser.dart' show
8 FormalParameterType,
9 optional;
10
11 import 'package:dart_parser/src/error_kind.dart' show
12 ErrorKind;
13
14 import 'package:kernel/ast.dart';
15
16 import 'package:kernel/clone.dart' show
17 CloneVisitor;
18
19 import 'package:kernel/transformations/flags.dart' show
20 TransformerFlag;
21
22 import 'package:kernel/class_hierarchy.dart' show
23 ClassHierarchy;
24
25 import 'package:kernel/core_types.dart' show
26 CoreTypes;
27
28 import 'package:dart_scanner/src/token.dart' show
29 BeginGroupToken,
30 ErrorToken,
31 Token,
32 isBinaryOperator,
33 isMinusOperator;
34
35 import '../errors.dart' show
36 InputError,
37 internalError;
38
39 import '../errors.dart' as errors show
40 inputError;
41
42 import '../source/scope_listener.dart' show
43 JumpTargetKind,
44 NullValue,
45 ScopeListener;
46
47 import '../builder/scope.dart' show
48 AccessErrorBuilder,
49 AmbiguousBuilder,
50 Scope;
51
52 import '../source/outline_builder.dart' show
53 asyncMarkerFromTokens;
54
55 import 'builder_accessors.dart';
56
57 import 'frontend_accessors.dart' show
58 buildIsNull,
59 makeBinary,
60 makeLet;
61
62 import 'builder_accessors.dart' as builder_accessors show
63 throwNoSuchMethodError;
64
65 import '../quote.dart' show
66 Quote,
67 analyzeQuote,
68 unescape,
69 unescapeFirstStringPart,
70 unescapeLastStringPart,
71 unescapeString;
72
73 import '../modifier.dart' show
74 Modifier,
75 constMask,
76 finalMask;
77
78 import 'redirecting_factory_body.dart' show
79 getRedirectionTarget;
80
81 import 'kernel_builder.dart';
82
83 const bool showNits = false;
84
85 final Name callName = new Name("call");
86
87 final Name plusName = new Name("+");
88
89 final Name minusName = new Name("-");
90
91 final Name multiplyName = new Name("*");
92
93 final Name divisionName = new Name("/");
94
95 final Name percentName = new Name("%");
96
97 final Name ampersandName = new Name("&");
98
99 final Name leftShiftName = new Name("<<");
100
101 final Name rightShiftName = new Name(">>");
102
103 final Name caretName = new Name("^");
104
105 final Name barName = new Name("|");
106
107 final Name mustacheName = new Name("~/");
108
109 class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
110 final KernelLibraryBuilder library;
111
112 final MemberBuilder member;
113
114 final KernelClassBuilder classBuilder;
115
116 final ClassHierarchy hierarchy;
117
118 final CoreTypes coreTypes;
119
120 final bool isInstanceMember;
121
122 final Map<String, FieldInitializer> fieldInitializers =
123 <String, FieldInitializer>{};
124
125 final Scope enclosingScope;
126
127 Scope formalParameterScope;
128
129 bool isFirstIdentifier = false;
130
131 bool hasParserError = false;
132
133 bool inInitializer = false;
134
135 bool inCatchClause = false;
136
137 int functionNestingLevel = 0;
138
139 Statement compileTimeErrorInTry;
140
141 Statement compileTimeErrorInLoopOrSwitch;
142
143 Scope switchScope;
144
145 CloneVisitor cloner;
146
147 BodyBuilder(this.library, this.member, Scope scope, this.formalParameterScope,
148 this.hierarchy, this.coreTypes, this.classBuilder, this.isInstanceMember)
149 : enclosingScope = scope,
150 super(scope);
151
152 bool get inConstructor {
153 return functionNestingLevel == 0 && member is KernelConstructorBuilder;
154 }
155
156 bool get isInstanceContext {
157 return isInstanceMember || member is KernelConstructorBuilder;
158 }
159
160 void push(Object node) {
161 isFirstIdentifier = false;
162 inInitializer = false;
163 super.push(node);
164 }
165
166 Expression popForValue() => toValue(pop());
167
168 Expression popForEffect() => toEffect(pop());
169
170 Expression toValue(Object node) {
171 if (node is UnresolvedIdentifier) {
172 return throwNoSuchMethodError(node.name.name, new Arguments.empty(),
173 node.fileOffset, isGetter: true);
174 } else if (node is BuilderAccessor) {
175 return node.buildSimpleRead();
176 } else if (node is TypeVariableBuilder) {
177 TypeParameterType type = node.buildTypesWithBuiltArguments(null);
178 if (!isInstanceContext && type.parameter.parent is Class) {
179 return buildCompileTimeError(
180 "Type variables can only be used in instance methods.");
181 } else {
182 return new TypeLiteral(type);
183 }
184 } else if (node is TypeDeclarationBuilder) {
185 return new TypeLiteral(node.buildTypesWithBuiltArguments(null));
186 } else if (node is KernelTypeBuilder) {
187 return new TypeLiteral(node.build());
188 } else if (node is Expression) {
189 return node;
190 } else if (node is PrefixBuilder) {
191 return buildCompileTimeError("A library can't be used as an expression.");
192 } else {
193 return internalError("Unhandled: ${node.runtimeType}");
194 }
195 }
196
197 Expression toEffect(Object node) {
198 if (node is BuilderAccessor) return node.buildForEffect();
199 return toValue(node);
200 }
201
202 List<Expression> popListForValue(int n) {
203 List<Expression> list =
204 new List<Expression>.filled(n, null, growable: true);
205 for (int i = n - 1; i >= 0; i--) {
206 list[i] = popForValue();
207 }
208 return list;
209 }
210
211 List<Expression> popListForEffect(int n) {
212 List<Expression> list =
213 new List<Expression>.filled(n, null, growable: true);
214 for (int i = n - 1; i >= 0; i--) {
215 list[i] = popForEffect();
216 }
217 return list;
218 }
219
220 Block popBlock(int count) {
221 List<Statement> statements = popList(count) ?? <Statement>[];
222 List<Statement> copy;
223 for (int i = 0; i < statements.length; i++) {
224 var statement = statements[i];
225 if (statement is List) {
226 copy ??= new List<Statement>.from(statements.getRange(0, i));
227 copy.addAll(statement);
228 } else if (copy != null) {
229 copy.add(statement);
230 }
231 }
232 return new Block(copy ?? statements);
233 }
234
235 Statement popStatementIfNotNull(Object value) {
236 return value == null ? null : popStatement();
237 }
238
239 Statement popStatement() {
240 var statement = pop();
241 if (statement is List) {
242 return new Block(new List<Statement>.from(statement));
243 } else {
244 return statement;
245 }
246 }
247
248 void ignore(Unhandled value) {
249 pop();
250 }
251
252 void enterSwitchScope() {
253 push(switchScope ?? NullValue.SwitchScope);
254 switchScope = scope;
255 }
256
257 void exitSwitchScope() {
258 switchScope = pop();
259 }
260
261 Uri get uri => library.fileUri ?? library.uri;
262
263 JumpTarget createJumpTarget(JumpTargetKind kind) => new JumpTarget(kind);
264
265 void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
266 debugEvent("Metadata");
267 pop(); // Arguments.
268 popIfNotNull(periodBeforeName); // Postfix.
269 pop(); // Type arguments.
270 pop(); // Expression or type name (depends on arguments).
271 // TODO(ahe): Implement metadata on local declarations.
272 }
273
274 void endMetadataStar(int count, bool forParameter) {
275 debugEvent("MetadataStar");
276 push(NullValue.Metadata);
277 }
278
279 void endTopLevelFields(int count, Token beginToken, Token endToken) {
280 debugEvent("TopLevelFields");
281 doFields(count);
282 }
283
284 void endFields(int count, Token beginToken, Token endToken) {
285 debugEvent("Fields");
286 doFields(count);
287 pop(); // Metadata.
asgerf 2017/01/16 11:52:26 Why metadata here, but not for top-level fields?
ahe 2017/01/16 12:32:38 It's due to a difference between parseMember and p
288 }
289
290 void doFields(int count) {
291 List nodes = popList(count);
292 pop(); // Type.
293 pop(); // Modifiers.
294 for (var node in nodes) {
295 if (node is Identifier) {
296 // Ignore, there's no initializer.
297 } else if (node is VariableDeclaration) {
298 FieldBuilder field;
299 if (classBuilder != null) {
300 field = classBuilder.members[node.name];
301 } else {
302 field = library.members[node.name];
303 }
304 if (field.next != null) {
305 // TODO(ahe): This can happen, for example, if a final field is
306 // combined with a setter.
307 internalError(
308 "Unhandled: '${field.name}' has more than one declaration.");
309 }
310 field.initializer = node.initializer;
311 } else {
312 internalError("Unhandled: ${node.runtimeType}");
313 }
314 }
315 }
316
317 void endMember() {
318 debugEvent("Member");
319 checkEmpty();
320 }
321
322 void endFunctionBody(int count, Token beginToken, Token endToken) {
323 debugEvent("FunctionBody");
324 if (beginToken == null) {
325 assert(count == 0);
326 push(NullValue.Block);
327 } else {
328 Block block = popBlock(count);
329 exitLocalScope();
330 push(block);
331 }
332 }
333
334 void prepareInitializers() {
335 scope = formalParameterScope;
336 assert(fieldInitializers.isEmpty);
337 final member = this.member;
338 if (member is KernelConstructorBuilder) {
339 Constructor constructor = member.constructor;
340 classBuilder.members.forEach((String name, Builder builder) {
341 if (builder is KernelFieldBuilder && builder.isInstanceMember) {
342 // TODO(ahe): Compute initializers (as in `field = initializer`).
343 fieldInitializers[name] = new FieldInitializer(builder.field, null)
344 ..parent = constructor;
345 }
346 });
347 if (member.formals != null) {
348 for (KernelFormalParameterBuilder formal in member.formals) {
349 if (formal.hasThis) {
350 FieldInitializer initializer = fieldInitializers[formal.name];
351 if (initializer != null) {
352 fieldInitializers.remove(formal.name);
353 initializer.value = new VariableGet(formal.declaration)
354 ..parent = initializer;
355 member.addInitializer(initializer);
356 }
357 }
358 }
359 }
360 }
361 }
362
363 void beginConstructorInitializer(Token token) {
364 debugEvent("beginConstructorInitializer");
365 inInitializer = true;
366 }
367
368 void endConstructorInitializer(Token token) {
369 debugEvent("endConstructorInitializer");
370 assert(!inInitializer);
371 final member = this.member;
372 var node = pop();
373 Initializer initializer;
374 if (node is Initializer) {
375 initializer = node;
376 } else if (node is BuilderAccessor) {
377 initializer = node.buildFieldInitializer(fieldInitializers);
378 } else if (node is ConstructorInvocation) {
379 initializer = new SuperInitializer(node.target, node.arguments);
380 } else {
381 if (node is !Throw) {
382 node = wrapInvalid(node);
383 }
384 initializer =
385 new LocalInitializer(new VariableDeclaration.forValue(node));
386 }
387 if (member is KernelConstructorBuilder) {
388 member.addInitializer(initializer);
389 } else {
390 inputError("Can't have initializers: ${member.name}", token.charOffset);
391 }
392 }
393
394 void handleNoInitializers() {
395 debugEvent("NoInitializers");
396 }
397
398 void endInitializers(int count, Token beginToken, Token endToken) {
399 debugEvent("Initializers");
400 }
401
402 void finishFunction(FormalParameters formals,
403 AsyncMarker asyncModifier, Statement body) {
404 debugEvent("finishFunction");
405 KernelFunctionBuilder builder = member;
406 if (builder is KernelConstructorBuilder) {
407 if (asyncModifier != AsyncMarker.Sync) {
408 // TODO(ahe): Change this to a null check.
409 inputError("Can't be marked as ${asyncModifier}: ${builder.name}",
410 body?.fileOffset);
411 }
412 } else if (builder is KernelProcedureBuilder) {
413 builder.asyncModifier = asyncModifier;
414 } else {
415 internalError("Unhandled: ${builder.runtimeType}");
416 }
417 builder.body = body;
418 if (formals?.optional != null) {
419 Iterator<FormalParameterBuilder> formalBuilders =
420 builder.formals.skip(formals.required.length).iterator;
421 for (VariableDeclaration parameter in formals.optional.formals) {
422 bool hasMore = formalBuilders.moveNext();
423 assert(hasMore);
424 VariableDeclaration realParameter = formalBuilders.current.target;
425 Expression initializer = parameter.initializer ?? new NullLiteral();
426 realParameter.initializer = initializer
427 ..parent = realParameter;
428 }
429 }
430 }
431
432 void endExpressionStatement(Token token) {
433 debugEvent("ExpressionStatement");
434 push(new ExpressionStatement(popForEffect()));
435 }
436
437 void endArguments(int count, Token beginToken, Token endToken) {
438 debugEvent("Arguments");
439 List arguments = popList(count) ?? <Expression>[];
440 int firstNamedArgument = arguments.length;
441 for (int i = 0; i < arguments.length; i++) {
442 var node = arguments[i];
443 if (node is NamedExpression) {
444 firstNamedArgument = i < firstNamedArgument ? i : firstNamedArgument;
445 } else {
446 arguments[i] = node = toValue(node);
447 if (i > firstNamedArgument) {
448 internalError("Expected named argument: $node");
449 }
450 }
451 }
452 if (firstNamedArgument < arguments.length) {
453 List<Expression> positional = new List<Expression>.from(
454 arguments.getRange(0, firstNamedArgument));
455 List<NamedExpression> named = new List<NamedExpression>.from(
456 arguments.getRange(firstNamedArgument,arguments.length));
457 push(new Arguments(positional, named: named));
458 } else {
459 push(new Arguments(arguments));
460 }
461 }
462
463 void handleParenthesizedExpression(BeginGroupToken token) {
464 debugEvent("ParenthesizedExpression");
465 push(popForValue());
466 }
467
468 void endSend(Token token) {
469 debugEvent("Send");
470 Arguments arguments = pop();
471 List typeArguments = pop();
472 Object receiver = pop();
473 if (arguments != null && typeArguments != null) {
474 arguments.types.addAll(typeArguments);
475 } else {
476 assert(typeArguments == null);
477 }
478 if (receiver is Identifier) {
479 Name name = new Name(receiver.name, library.library);
480 if (arguments == null) {
481 push(new IncompletePropertyAccessor(this, token.charOffset, name));
482 } else {
483 push(new SendAccessor(this, token.charOffset, name, arguments));
484 }
485 } else if (arguments == null) {
486 push(receiver);
487 } else {
488 push(finishSend(receiver, arguments, token.charOffset));
489 }
490 }
491
492 finishSend(Object receiver, Arguments arguments, int charOffset) {
493 if (receiver is BuilderAccessor) {
494 return receiver.doInvocation(charOffset, arguments);
495 } else if (receiver is UnresolvedIdentifier) {
496 return throwNoSuchMethodError(receiver.name.name, arguments,
497 receiver.fileOffset);
498 } else {
499 return buildMethodInvocation(toValue(receiver), callName,
500 arguments, charOffset);
501 }
502 }
503
504 void beginCascade(Token token) {
505 debugEvent("beginCascade");
506 Expression expression = popForValue();
507 if (expression is CascadeReceiver) {
508 push(expression);
509 push(new VariableAccessor(
510 this, expression.fileOffset, expression.variable));
511 expression.extend();
512 } else {
513 VariableDeclaration variable =
514 new VariableDeclaration.forValue(expression);
515 push(new CascadeReceiver(variable));
516 push(new VariableAccessor(this, expression.fileOffset, variable));
517 }
518 }
519
520 void endCascade() {
521 debugEvent("endCascade");
522 Expression expression = popForEffect();
523 CascadeReceiver cascadeReceiver = pop();
524 cascadeReceiver.finalize(expression);
525 push(cascadeReceiver);
526 }
527
528 void handleBinaryExpression(Token token) {
529 debugEvent("BinaryExpression");
530 if (optional(".", token) || optional("..", token)) {
531 return doDotOrCascadeExpression(token);
532 }
533 if (optional("&&", token) || optional("||", token)) {
534 return doLogicalExpression(token);
535 }
536 if (optional("??", token)) return doIfNull(token);
537 if (optional("?.", token)) return doIfNotNull(token);
538 Expression argument = popForValue();
539 var receiver = pop();
540 bool isSuper = false;
541 if (receiver is ThisAccessor && receiver.isSuper) {
542 isSuper = true;
543 receiver = new ThisExpression();
544 }
545 push(buildBinaryOperator(toValue(receiver), token, argument, isSuper));
546 }
547
548 Expression buildBinaryOperator(Expression a, Token token, Expression b,
549 bool isSuper) {
550 bool negate = false;
551 String operator = token.stringValue;
552 if (identical("!=", operator)) {
553 operator = "==";
554 negate = true;
555 }
556 if (!isBinaryOperator(operator) && !isMinusOperator(operator)) {
557 return buildCompileTimeError("Not an operator: '$operator'.",
558 token.charOffset);
559 } else {
560 Expression result = makeBinary(a, new Name(operator), null, b);
561 if (isSuper) {
562 result = toSuperMethodInvocation(result);
563 }
564 return negate ? new Not(result) : result;
565 }
566 }
567
568 void doLogicalExpression(Token token) {
569 Expression argument = popForValue();
570 Expression receiver = popForValue();
571 push(new LogicalExpression(receiver, token.stringValue, argument));
572 }
573
574 /// Handle `a ?? b`.
575 void doIfNull(Token token) {
576 Expression b = popForValue();
577 Expression a = popForValue();
578 VariableDeclaration variable = new VariableDeclaration.forValue(a);
579 push(makeLet(variable,
580 new ConditionalExpression(buildIsNull(new VariableGet(variable)),
581 b, new VariableGet(variable), const DynamicType())));
582 }
583
584 /// Handle `a?.b(...)`.
585 void doIfNotNull(Token token) {
586 IncompleteSend send = pop();
587 push(send.withReceiver(pop(), isNullAware: true));
588 }
589
590 void doDotOrCascadeExpression(Token token) {
591 // TODO(ahe): Handle null-aware.
592 IncompleteSend send = pop();
593 Object receiver = optional(".", token) ? pop() : popForValue();
594 push(send.withReceiver(receiver));
595 }
596
597 Expression toSuperMethodInvocation(MethodInvocation node) {
598 Member target = lookupSuperMember(node.name);
599 bool isNoSuchMethod = target == null;
600 if (target is Procedure) {
601 if (!target.isAccessor) {
602 if (areArgumentsCompatible(target.function, node.arguments)) {
603 // TODO(ahe): Use [DirectMethodInvocation] when possible.
604 Expression result = new DirectMethodInvocation(new ThisExpression(),
605 target, node.arguments);
606 result = new SuperMethodInvocation(node.name, node.arguments, null);
607 return result;
608 } else {
609 isNoSuchMethod = true;
610 }
611 }
612 }
613 if (isNoSuchMethod) {
614 return throwNoSuchMethodError(
615 node.name.name, node.arguments, node.fileOffset, isSuper: true);
616 }
617 // TODO(ahe): Use [DirectPropertyGet] when possible.
618 Expression receiver = new DirectPropertyGet(new ThisExpression(), target);
619 receiver = new SuperPropertyGet(node.name, target);
620 return buildMethodInvocation(receiver, callName, node.arguments,
621 node.fileOffset);
622 }
623
624 bool areArgumentsCompatible(FunctionNode function, Arguments arguments) {
625 // TODO(ahe): Implement this.
626 return true;
627 }
628
629 Expression throwNoSuchMethodError(String name, Arguments arguments,
630 int charOffset, {bool isSuper: false, isGetter: false, isSetter: false}) {
631 return builder_accessors.throwNoSuchMethodError(name, arguments, uri,
632 charOffset, coreTypes, isSuper: isSuper, isGetter: isGetter,
633 isSetter: isSetter);
634 }
635
636 Member lookupSuperMember(Name name, {bool isSetter: false}) {
637 Class superclass = classBuilder.cls.superclass;
638 return superclass == null
639 ? null
640 : hierarchy.getDispatchTarget(superclass, name, setter: isSetter);
641 }
642
643 Constructor lookupConstructor(Name name, {bool isSuper}) {
644 Class cls = classBuilder.cls;
645 if (isSuper) {
646 cls = cls.superclass;
647 while (cls.isMixinApplication) {
648 cls = cls.superclass;
649 }
650 }
651 if (cls != null) {
652 for (Constructor constructor in cls.constructors) {
653 if (constructor.name == name) return constructor;
654 }
655 }
656 return null;
657 }
658
659 void beginExpression(Token token) {
660 debugEvent("beginExpression");
661 isFirstIdentifier = true;
662 }
663
664 Builder computeSetter(Builder builder, Scope scope, String name) {
665 if (builder.isSetter) return builder;
666 if (builder.isGetter) return scope.lookupSetter(name);
667 return builder.isField ? (builder.isFinal ? null : builder) : null;
668 }
669
670 void handleIdentifier(Token token) {
671 debugEvent("handleIdentifier");
672 String name = token.value;
673 if (isFirstIdentifier) {
674 assert(!inInitializer || this.scope == enclosingScope ||
675 this.scope.parent == enclosingScope);
676 // This deals with this kind of initializer: `C(a) : a = a;`
677 Scope scope = inInitializer ? enclosingScope : this.scope;
678 Builder builder = scope.lookup(name);
679 push(builderToFirstExpression(builder, name, token.charOffset));
680 } else {
681 push(new Identifier(name)..fileOffset = token.charOffset);
682 }
683 }
684
685 builderToFirstExpression(Builder builder, String name, int charOffset,
686 {bool isPrefix: false}) {
687 if (builder == null || (!isInstanceContext && builder.isInstanceMember)) {
688 if (!isPrefix && identical(name, "dynamic") && builder == null) {
689 return new KernelInterfaceTypeBuilder(name, null);
690 }
691 Name n = new Name(name, library.library);
692 if (!isPrefix && isInstanceContext) {
693 assert(builder == null);
694 return new ThisPropertyAccessor(this, charOffset, n, null, null);
695 } else {
696 return new UnresolvedIdentifier(n)
697 ..fileOffset = charOffset;
698 }
699 } else if (builder.isTypeDeclaration) {
700 return builder;
701 } else if (builder.isLocal) {
702 return new VariableAccessor(this, charOffset, builder.target);
703 } else if (builder.isInstanceMember) {
704 return new ThisPropertyAccessor(this, charOffset,
705 new Name(name, library.library), null, null);
706 } else if (builder.isRegularMethod) {
707 assert(builder.isStatic || builder.isTopLevel);
708 return new StaticAccessor(this, charOffset, builder.target, null);
709 } else if (builder is PrefixBuilder) {
710 return builder;
711 } else if (builder is MixedAccessor) {
712 return new StaticAccessor(this, charOffset, builder.getter.target,
713 builder.setter.target);
714 } else {
715 if (builder is AccessErrorBuilder) {
716 AccessErrorBuilder error = builder;
717 builder = error.builder;
718 }
719 if (builder.target == null) {
720 return internalError("Unhandled: ${builder}");
721 }
722 Member getter = builder.target.hasGetter ? builder.target : null;
723 Member setter = builder.target.hasSetter ? builder.target : null;
724 setter ??= computeSetter(builder, scope, name)?.target;
725 return
726 new StaticAccessor(this, charOffset, getter, setter);
727 }
728 }
729
730 void handleQualified(Token period) {
731 debugEvent("Qualified");
732 Identifier name = pop();
733 var receiver = pop();
734 push([receiver, name]);
735 }
736
737 void beginLiteralString(Token token) {
738 debugEvent("beginLiteralString");
739 push(token);
740 }
741
742 void handleStringPart(Token token) {
743 debugEvent("StringPart");
744 push(token);
745 }
746
747 void endLiteralString(int interpolationCount) {
748 debugEvent("endLiteralString");
749 if (interpolationCount == 0) {
750 Token token = pop();
751 push(new StringLiteral(unescapeString(token.value)));
752 } else {
753 List parts = popList(1 + interpolationCount * 2);
754 Token first = parts.first;
755 Token last = parts.last;
756 Quote quote = analyzeQuote(first.value);
757 List<Expression> expressions = <Expression>[];
758 expressions.add(new StringLiteral(unescapeFirstStringPart(
759 first.value, quote)));
760 for (int i = 1; i < parts.length - 1; i++) {
761 var part = parts[i];
762 if (part is Token) {
763 expressions.add(new StringLiteral(unescape(part.value, quote)));
764 } else {
765 expressions.add(toValue(part));
766 }
767 }
768 expressions.add(
769 new StringLiteral(unescapeLastStringPart(last.value, quote)));
770 push(new StringConcatenation(expressions));
771 }
772 }
773
774 void handleStringJuxtaposition(int literalCount) {
775 debugEvent("StringJuxtaposition");
776 List<Expression> parts = popListForValue(literalCount);
777 List<Expression> expressions;
778 // Flatten string juxtapositions of string interpolation.
779 for (int i = 0; i < parts.length; i++) {
780 Expression part = parts[i];
781 if (part is StringConcatenation) {
782 if (expressions == null) {
783 expressions = parts.sublist(0, i);
784 }
785 expressions.addAll(part.expressions);
786 } else {
787 if (expressions != null) {
788 expressions.add(part);
789 }
790 }
791 }
792 push(new StringConcatenation(expressions ?? parts));
793 }
794
795 void handleLiteralInt(Token token) {
796 debugEvent("LiteralInt");
797 push(new IntLiteral(int.parse(token.value)));
798 }
799
800 void endReturnStatement(
801 bool hasExpression, Token beginToken, Token endToken) {
802 debugEvent("ReturnStatement");
803 Expression expression = hasExpression ? popForValue() : null;
804 if (expression != null && inConstructor) {
805 push(buildCompileTimeErrorStatement("Can't return from a constructor.",
806 beginToken.charOffset));
807 } else {
808 push(new ReturnStatement(expression));
809 }
810 }
811
812 void endIfStatement(Token ifToken, Token elseToken) {
813 Statement elsePart = popStatementIfNotNull(elseToken);
814 Statement thenPart = popStatement();
815 Expression condition = popForValue();
816 push(new IfStatement(condition, thenPart, elsePart));
817 }
818
819 void endInitializer(Token assignmentOperator) {
820 debugEvent("Initializer");
821 assert(assignmentOperator.stringValue == "=");
822 Expression initializer = popForValue();
823 Identifier identifier = pop();
824 push(new VariableDeclaration(identifier.name, initializer: initializer));
825 }
826
827 void endInitializedIdentifier() {
828 // TODO(ahe): Use [InitializedIdentifier] here?
829 debugEvent("InitializedIdentifier");
830 TreeNode node = pop();
831 VariableDeclaration variable;
832 if (node is VariableDeclaration) {
833 variable = node;
834 } else if (node is Identifier) {
835 variable = new VariableDeclaration(node.name);
836 } else {
837 internalError("unhandled identifier: ${node.runtimeType}");
838 }
839 push(variable);
840 scope[variable.name] = new KernelVariableBuilder(variable);
841 }
842
843 void endVariablesDeclaration(int count, Token endToken) {
844 debugEvent("VariablesDeclaration");
845 List<VariableDeclaration> variables = popList(count);
846 DartType type = pop();
847 int modifiers = Modifier.validate(pop());
848 bool isConst = (modifiers & constMask) != 0;
849 bool isFinal = (modifiers & finalMask) != 0;
850 if (type != null || isConst || isFinal) {
851 type ??= const DynamicType();
852 for (VariableDeclaration variable in variables) {
853 variable
854 ..type = type
855 ..isConst = isConst
856 ..isFinal = isFinal;
857 }
858 }
859 if (variables.length != 1) {
860 push(variables);
861 } else {
862 push(variables.single);
863 }
864 }
865
866 void endBlock(int count, Token beginToken, Token endToken) {
867 debugEvent("Block");
868 Block block = popBlock(count);
869 exitLocalScope();
870 push(block);
871 }
872
873 void handleAssignmentExpression(Token token) {
874 debugEvent("AssignmentExpression");
875 Expression value = popForValue();
876 var accessor = pop();
877 if (accessor is TypeDeclarationBuilder) {
878 push(wrapInvalid(
879 new TypeLiteral(accessor.buildTypesWithBuiltArguments(null))));
880 } else if (accessor is! BuilderAccessor) {
881 push(buildCompileTimeError("Can't assign to this.", token.charOffset));
882 } else {
883 push(new DelayedAssignment(this, token.charOffset, accessor, value,
884 token.stringValue));
885 }
886 }
887
888 void enterLoop() {
889 if (peek() is LabelTarget) {
890 LabelTarget target = peek();
891 enterBreakTarget(target.breakTarget);
892 enterContinueTarget(target.continueTarget);
893 } else{
894 enterBreakTarget();
895 enterContinueTarget();
896 }
897 }
898
899 void exitLoopOrSwitch(Statement statement) {
900 if (compileTimeErrorInLoopOrSwitch != null) {
901 push(compileTimeErrorInLoopOrSwitch);
902 compileTimeErrorInLoopOrSwitch = null;
903 } else {
904 push(statement);
905 }
906 }
907
908 void endForStatement(
909 int updateExpressionCount, Token beginToken, Token endToken) {
910 debugEvent("ForStatement");
911 Statement body = popStatement();
912 List<Expression> updates = popListForEffect(updateExpressionCount);
913 Statement conditionStatement = popStatement();
914 Expression condition = null;
915 if (conditionStatement is ExpressionStatement) {
916 condition = conditionStatement.expression;
917 } else {
918 assert(conditionStatement is EmptyStatement);
919 }
920 List<VariableDeclaration> variables = <VariableDeclaration>[];
921 var variableOrExpression = pop();
922 Statement begin;
923 if (variableOrExpression is BuilderAccessor) {
924 variableOrExpression = variableOrExpression.buildForEffect();
925 }
926 if (variableOrExpression is VariableDeclaration) {
927 variables.add(variableOrExpression);
928 } else if (variableOrExpression is List) {
929 variables.addAll(variableOrExpression);
930 } else if (variableOrExpression == null) {
931 // Do nothing.
932 } else if (variableOrExpression is Expression) {
933 begin = new ExpressionStatement(variableOrExpression);
934 } else {
935 return internalError("Unhandled: ${variableOrExpression.runtimeType}");
936 }
937 exitLocalScope();
938 JumpTarget continueTarget = exitContinueTarget();
939 JumpTarget breakTarget = exitBreakTarget();
940 if (continueTarget.hasUsers) {
941 body = new LabeledStatement(body);
942 continueTarget.resolveContinues(body);
943 }
944 Statement result = new ForStatement(variables, condition, updates, body);
945 if (begin != null) {
946 result = new Block(<Statement>[begin, result]);
947 }
948 if (breakTarget.hasUsers) {
949 result = new LabeledStatement(result);
950 breakTarget.resolveBreaks(result);
951 }
952 exitLoopOrSwitch(result);
953 }
954
955 void endAwaitExpression(Token beginToken, Token endToken) {
956 debugEvent("AwaitExpression");
957 push(new AwaitExpression(popForValue()));
958 }
959
960 void handleAsyncModifier(Token asyncToken, Token starToken) {
961 debugEvent("AsyncModifier");
962 push(asyncMarkerFromTokens(asyncToken, starToken));
963 }
964
965 void handleLiteralList(
966 int count, Token beginToken, Token constKeyword, Token endToken) {
967 debugEvent("LiteralList");
968 List<Expression> expressions = popListForValue(count);
969 List<DartType> typeArguments = pop();
970 DartType typeArgument = const DynamicType();
971 if (typeArguments != null) {
972 typeArgument = typeArguments.first;
973 if (typeArguments.length > 1) {
974 typeArgument = const DynamicType();
975 warning("Too many type arguments on List literal.",
976 beginToken.charOffset);
977 }
978 }
979 push(new ListLiteral(expressions, typeArgument: typeArgument,
980 isConst: constKeyword != null));
981 }
982
983 void handleLiteralBool(Token token) {
984 debugEvent("LiteralBool");
985 bool value = optional("true", token);
986 assert(value || optional("false", token));
987 push(new BoolLiteral(value));
988 }
989
990 void handleLiteralDouble(Token token) {
991 debugEvent("LiteralDouble");
992 push(new DoubleLiteral(double.parse(token.value)));
993 }
994
995 void handleLiteralNull(Token token) {
996 debugEvent("LiteralNull");
997 push(new NullLiteral());
998 }
999
1000 void handleLiteralMap(
1001 int count, Token beginToken, Token constKeyword, Token endToken) {
1002 debugEvent("LiteralMap");
1003 List<MapEntry> entries = popList(count) ?? <MapEntry>[];
1004 List<DartType> typeArguments = pop();
1005 DartType keyType = const DynamicType();
1006 DartType valueType = const DynamicType();
1007 if (typeArguments != null) {
1008 if (typeArguments.length != 2) {
1009 keyType = const DynamicType();
1010 valueType = const DynamicType();
1011 warning("Map literal requires two type arguments.",
1012 beginToken.charOffset);
1013 } else {
1014 keyType = typeArguments[0];
1015 valueType = typeArguments[1];
1016 }
1017 }
1018 push(new MapLiteral(entries, keyType: keyType, valueType: valueType,
1019 isConst: constKeyword != null));
1020 }
1021
1022 void endLiteralMapEntry(Token colon, Token endToken) {
1023 debugEvent("LiteralMapEntry");
1024 Expression value = popForValue();
1025 Expression key = popForValue();
1026 push(new MapEntry(key, value));
1027 }
1028
1029 void beginLiteralSymbol(Token token) {
1030 isFirstIdentifier = false;
1031 }
1032
1033 String symbolPartToString(name) {
1034 if (name is Identifier) {
1035 return name.name;
1036 } else if (name is Operator) {
1037 return name.name;
1038 } else {
1039 return internalError("Unhandled: ${name.runtimeType}");
1040 }
1041 }
1042
1043 void endLiteralSymbol(Token hashToken, int identifierCount) {
1044 debugEvent("LiteralSymbol");
1045 String value;
1046 if (identifierCount == 1) {
1047 value = symbolPartToString(popForValue());
1048 } else {
1049 List parts = popList(identifierCount);
1050 value = symbolPartToString(parts.first);
1051 for (int i = 1; i < parts.length; i++) {
1052 value += ".${symbolPartToString(parts[i])}";
1053 }
1054 }
1055 push(new SymbolLiteral(value));
1056 }
1057
1058 DartType toKernelType(String name, List<DartType> arguments) {
1059 if (identical(name, "void")) return const VoidType();
1060 if (identical(name, "dynamic")) return const DynamicType();
1061 Builder builder = scope.lookup(name);
1062 if (builder is TypeDeclarationBuilder) {
1063 return builder.buildTypesWithBuiltArguments(arguments);
1064 }
1065 if (builder == null) {
1066 print("$uri: Type not found: $name");
1067 } else {
1068 print("$uri: Not a type: $name");
1069 }
1070 // TODO(ahe): Create an error somehow.
1071 return const DynamicType();
1072 }
1073
1074 void endType(Token beginToken, Token endToken) {
1075 // TODO(ahe): The scope is wrong for return types of generic functions.
1076 debugEvent("Type");
1077 List<DartType> arguments = pop();
1078 var name = pop();
1079 if (name is List) {
1080 if (name.length != 2) {
1081 return internalError("Unexpected: $name.length");
1082 }
1083 var prefix = name[0];
1084 if (prefix is Identifier) {
1085 prefix = prefix.name;
1086 }
1087 var suffix = name[1];
1088 if (suffix is Identifier) {
1089 suffix = suffix.name;
1090 }
1091 Builder builder;
1092 if (prefix is Builder) {
1093 builder = prefix;
1094 } else {
1095 builder = scope.lookup(prefix);
1096 }
1097 if (builder is PrefixBuilder) {
1098 name = builder.exports[suffix];
1099 } else {
1100 return inputError(
1101 "Can't be used as a type: '${debugName(prefix, suffix)}'.",
1102 beginToken.charOffset);
1103 }
1104 }
1105 if (name is Identifier) {
1106 name = name.name;
1107 }
1108 if (name is BuilderAccessor) {
1109 warning("'${beginToken.value}' isn't a type.", beginToken.charOffset);
1110 push(const DynamicType());
1111 } else if (name is UnresolvedIdentifier) {
1112 warning("'${name.name}' isn't a type.", beginToken.charOffset);
1113 push(const DynamicType());
1114 } else if (name is TypeVariableBuilder) {
1115 push(name.buildTypesWithBuiltArguments(arguments));
1116 } else if (name is TypeDeclarationBuilder) {
1117 push(name.buildTypesWithBuiltArguments(arguments));
1118 } else if (name is TypeBuilder) {
1119 push(name.build());
1120 } else {
1121 push(toKernelType(name, arguments));
1122 }
1123 if (peek() is TypeParameterType) {
1124 TypeParameterType type = peek();
1125 if (!isInstanceContext && type.parameter.parent is Class) {
1126 pop();
1127 warning("Type variables can only be used in instance methods.",
1128 beginToken.charOffset);
1129 push(const DynamicType());
1130 }
1131 }
1132 }
1133
1134 void handleVoidKeyword(Token token) {
1135 debugEvent("VoidKeyword");
1136 push(const VoidType());
1137 }
1138
1139 void handleAsOperator(Token operator, Token endToken) {
1140 debugEvent("AsOperator");
1141 DartType type = pop();
1142 Expression expression = popForValue();
1143 push(new AsExpression(expression, type));
1144 }
1145
1146 void handleIsOperator(Token operator, Token not, Token endToken) {
1147 debugEvent("IsOperator");
1148 DartType type = pop();
1149 Expression expression = popForValue();
1150 expression = new IsExpression(expression, type);
1151 if (not != null) {
1152 expression = new Not(expression);
1153 }
1154 push(expression);
1155 }
1156
1157 void handleConditionalExpression(Token question, Token colon) {
1158 debugEvent("ConditionalExpression");
1159 Expression elseExpression = popForValue();
1160 Expression thenExpression = popForValue();
1161 Expression condition = popForValue();
1162 push(new ConditionalExpression(
1163 condition, thenExpression, elseExpression, const DynamicType()));
1164 }
1165
1166 void endThrowExpression(Token throwToken, Token endToken) {
1167 debugEvent("ThrowExpression");
1168 Expression expression = popForValue();
1169 push(new Throw(expression));
1170 }
1171
1172 void endFormalParameter(Token thisKeyword) {
1173 debugEvent("FormalParameter");
1174 if (thisKeyword != null) {
1175 if (!inConstructor) {
1176 return inputError("'this' parameters can only be used on constructors.",
1177 thisKeyword.charOffset);
1178 }
1179 }
1180 Identifier name = pop();
1181 DartType type = pop();
1182 pop(); // Modifiers.
1183 ignore(Unhandled.Metadata);
1184 VariableDeclaration variable;
1185 if (!inCatchClause && functionNestingLevel == 0) {
1186 var builder = formalParameterScope.lookup(name.name);
1187 if (builder == null) {
1188 return inputError("'${name.name}' isn't a field in this class.",
1189 name.fileOffset);
1190 }
1191 if (thisKeyword == null) {
1192 variable = builder.build();
1193 variable.initializer = name.initializer;
1194 } else if (builder.isField && builder.parent == classBuilder) {
1195 FieldBuilder field = builder;
1196 if (type != null) {
1197 nit("Ignoring type on 'this' parameter '${name.name}'.",
1198 name.fileOffset);
1199 }
1200 type = field.target.type ?? const DynamicType();
1201 variable = new VariableDeclaration(name.name, type: type,
1202 initializer: name.initializer);
1203 } else {
1204 return inputError("'${name.name}' isn't a field in this class.",
1205 name.fileOffset);
1206 }
1207 } else {
1208 variable = new VariableDeclaration(name.name,
1209 type: type ?? const DynamicType(), initializer: name.initializer);
1210 }
1211 push(variable);
1212 }
1213
1214 void endOptionalFormalParameters(
1215 int count, Token beginToken, Token endToken) {
1216 debugEvent("OptionalFormalParameters");
1217 FormalParameterType kind = optional("{", beginToken)
1218 ? FormalParameterType.NAMED : FormalParameterType.POSITIONAL;
1219 push(new OptionalFormals(kind, popList(count)));
1220 }
1221
1222 void beginFunctionTypedFormalParameter(Token token) {
1223 debugEvent("beginFunctionTypedFormalParameter");
1224 functionNestingLevel++;
1225 }
1226
1227 void handleFunctionTypedFormalParameter(Token token) {
1228 debugEvent("FunctionTypedFormalParameter");
1229 if (inCatchClause || functionNestingLevel != 0) {
1230 exitLocalScope();
1231 }
1232 FormalParameters formals = pop();
1233 ignore(Unhandled.TypeVariables);
1234 Identifier name = pop();
1235 DartType returnType = pop();
1236 push(formals.toFunctionType(returnType));
1237 push(name);
1238 functionNestingLevel--;
1239 }
1240
1241 void handleValuedFormalParameter(Token equals, Token token) {
1242 debugEvent("ValuedFormalParameter");
1243 Expression initializer = popForValue();
1244 Identifier name = pop();
1245 push(new InitializedIdentifier(name.name, initializer));
1246 }
1247
1248 void endFormalParameters(int count, Token beginToken, Token endToken) {
1249 debugEvent("FormalParameters");
1250 OptionalFormals optional;
1251 if (count > 0 && peek() is OptionalFormals) {
1252 optional = pop();
1253 count--;
1254 }
1255 FormalParameters formals = new FormalParameters(
1256 popList(count) ?? <VariableDeclaration>[], optional);
1257 push(formals);
1258 if (inCatchClause || functionNestingLevel != 0) {
1259 enterLocalScope(formals.computeFormalParameterScope(scope));
1260 }
1261 }
1262
1263 void beginCatchClause(Token token) {
1264 debugEvent("beginCatchClause");
1265 inCatchClause = true;
1266 }
1267
1268 void endCatchClause(Token token) {
1269 debugEvent("CatchClause");
1270 inCatchClause = false;
1271 }
1272
1273 void handleCatchBlock(Token onKeyword, Token catchKeyword) {
1274 debugEvent("CatchBlock");
1275 Block body = pop();
1276 if (catchKeyword != null) {
1277 exitLocalScope();
1278 }
1279 FormalParameters catchParameters = popIfNotNull(catchKeyword);
1280 DartType type = popIfNotNull(onKeyword) ?? const DynamicType();
1281 VariableDeclaration exception;
1282 VariableDeclaration stackTrace;
1283 if (catchParameters != null) {
1284 if (catchParameters.required.length > 0) {
1285 exception = catchParameters.required[0];
1286 }
1287 if (catchParameters.required.length > 1) {
1288 stackTrace = catchParameters.required[1];
1289 }
1290 if (catchParameters.required.length > 2 ||
1291 catchParameters.optional != null) {
1292 body = new Block(<Statement>[new InvalidStatement()]);
1293 compileTimeErrorInTry ??= buildCompileTimeErrorStatement(
1294 "Invalid catch arguments.", catchKeyword.next.charOffset);
1295 }
1296 }
1297 push(new Catch(exception, body, guard: type, stackTrace: stackTrace));
1298 }
1299
1300 void endTryStatement(
1301 int catchCount, Token tryKeyword, Token finallyKeyword) {
1302 Statement finallyBlock = popStatementIfNotNull(finallyKeyword);
1303 List<Catch> catches = popList(catchCount);
1304 Statement tryBlock = popStatement();
1305 if (compileTimeErrorInTry == null) {
1306 if (catches != null) {
1307 tryBlock = new TryCatch(tryBlock, catches);
1308 }
1309 if (finallyBlock != null) {
1310 tryBlock = new TryFinally(tryBlock, finallyBlock);
1311 }
1312 push(tryBlock);
1313 } else {
1314 push(compileTimeErrorInTry);
1315 compileTimeErrorInTry = null;
1316 }
1317 }
1318
1319 void handleNoExpression(Token token) {
1320 debugEvent("NoExpression");
1321 push(NullValue.Expression);
1322 }
1323
1324 void handleIndexedExpression(
1325 Token openCurlyBracket, Token closeCurlyBracket) {
1326 debugEvent("IndexedExpression");
1327 Expression index = popForValue();
1328 Expression receiver = popForValue();
1329 push(IndexAccessor.make(this, openCurlyBracket.charOffset, receiver, index,
1330 null, null));
1331 }
1332
1333 void handleUnaryPrefixExpression(Token token) {
1334 debugEvent("UnaryPrefixExpression");
1335 Expression expression = popForValue();
1336 if (optional("!", token)) {
1337 push(new Not(expression));
1338 } else {
1339 String operator = token.stringValue;
1340 if (optional("-", token)) {
1341 operator = "unary-";
1342 }
1343 push(buildMethodInvocation(expression, new Name(operator),
1344 new Arguments.empty(), token.charOffset));
1345 }
1346 }
1347
1348 Name incrementOperator(Token token) {
1349 if (optional("++", token)) return plusName;
1350 if (optional("--", token)) return minusName;
1351 return internalError("Unknown increment operator: ${token.value}");
1352 }
1353
1354 void handleUnaryPrefixAssignmentExpression(Token token) {
1355 debugEvent("UnaryPrefixAssignmentExpression");
1356 var accessor = pop();
1357 if (accessor is BuilderAccessor) {
1358 push(accessor.buildPrefixIncrement(incrementOperator(token)));
1359 } else {
1360 push(wrapInvalid(toValue(accessor)));
1361 }
1362 }
1363
1364 void handleUnaryPostfixAssignmentExpression(Token token) {
1365 debugEvent("UnaryPostfixAssignmentExpression");
1366 var accessor = pop();
1367 if (accessor is BuilderAccessor) {
1368 push(new DelayedPostfixIncrement(this, token.charOffset, accessor,
1369 incrementOperator(token), null));
1370 } else {
1371 push(wrapInvalid(toValue(accessor)));
1372 }
1373 }
1374
1375 void endConstructorReference(
1376 Token start, Token periodBeforeName, Token endToken) {
1377 debugEvent("ConstructorReference");
1378 // A constructor reference can contain up to three identifiers:
1379 //
1380 // a) type <type-arguments>?
1381 // b) type <type-arguments>? . name
1382 // c) prefix . type <type-arguments>?
1383 // d) prefix . type <type-arguments>? . name
1384 //
1385 // This isn't a legal constructor reference:
1386 //
1387 // type . name <type-arguments>
1388 //
1389 // But the parser can't tell this from type c) above.
1390 //
1391 // This method pops 2 (or 3 if periodBeforeName != null) values from the
1392 // stack and pushes 3 values: a type, a list of type arguments, and a name.
1393 //
1394 // If the constructor reference can be resolved, type is either a
1395 // ClassBuilder, or a ThisPropertyAccessor. Otherwise, it's an error that
1396 // should be handled later.
1397 Identifier suffix = popIfNotNull(periodBeforeName);
1398 Identifier identifier;
1399 List<DartType> typeArguments = pop();
1400 var type = pop();
1401 if (type is List) {
1402 var prefix = type[0];
1403 identifier = type[1];
1404 if (prefix is PrefixBuilder) {
1405 // TODO(ahe): Handle privacy in prefix.exports.
1406 type = builderToFirstExpression(
1407 prefix.exports[identifier.name], identifier.name, start.charOffset);
1408 identifier = null;
1409 } else if (prefix is ClassBuilder) {
1410 type = prefix;
1411 } else {
1412 type = new Identifier(start.value)..fileOffset = start.charOffset;
1413 }
1414 }
1415 String name;
1416 if (identifier != null && suffix != null) {
1417 name = "${identifier.name}.${suffix.name}";
1418 } else if (identifier != null) {
1419 name = identifier.name;
1420 } else if (suffix != null) {
1421 name = suffix.name;
1422 } else {
1423 name = "";
1424 }
1425 push(type);
1426 push(typeArguments ?? NullValue.TypeArguments);
1427 push(name);
1428 }
1429
1430 Expression buildStaticInvocation(Member target, Arguments arguments,
1431 {bool isConst: false}) {
1432 List<TypeParameter> typeParameters = target.function.typeParameters;
1433 if (target is Constructor) {
1434 typeParameters = target.enclosingClass.typeParameters;
1435 }
1436 if (!addDefaultArguments(target.function, arguments, typeParameters)) {
1437 return throwNoSuchMethodError(target.name.name, arguments, -1);
1438 }
1439 if (target is Constructor) {
1440 return new ConstructorInvocation(target, arguments)
1441 ..isConst = isConst;
1442 } else {
1443 return new StaticInvocation(target, arguments)
1444 ..isConst = isConst;
1445 }
1446 }
1447
1448 bool addDefaultArguments(FunctionNode function, Arguments arguments,
1449 List<TypeParameter> typeParameters) {
1450 bool missingInitializers = false;
1451
1452 Expression defaultArgumentFrom(Expression expression) {
1453 if (expression == null) {
1454 missingInitializers = true;
1455 return null;
1456 }
1457 cloner ??= new CloneVisitor();
1458 return cloner.clone(expression);
1459 }
1460
1461 if (arguments.positional.length < function.requiredParameterCount ||
1462 arguments.positional.length > function.positionalParameters.length) {
1463 return false;
1464 }
1465 for (int i = arguments.positional.length;
1466 i < function.positionalParameters.length;
1467 i++) {
1468 var expression =
1469 defaultArgumentFrom(function.positionalParameters[i].initializer);
1470 expression?.parent = arguments;
1471 arguments.positional.add(expression);
1472 }
1473 Map<String, VariableDeclaration> names;
1474 if (function.namedParameters.isNotEmpty) {
1475 names = <String, VariableDeclaration>{};
1476 for (VariableDeclaration parameter in function.namedParameters) {
1477 names[parameter.name] = parameter;
1478 }
1479 }
1480 if (arguments.named.isNotEmpty) {
1481 if (names == null) return false;
1482 for (NamedExpression argument in arguments.named) {
1483 VariableDeclaration parameter = names.remove(argument.name);
1484 if (parameter == null) {
1485 return false;
1486 }
1487 }
1488 }
1489 if (names != null) {
1490 for (String name in names.keys) {
1491 VariableDeclaration parameter = names[name];
1492 arguments.named.add(
1493 new NamedExpression(
1494 name, defaultArgumentFrom(parameter.initializer))
1495 ..parent = arguments);
1496 }
1497 }
1498 if (typeParameters.length != arguments.types.length) {
1499 arguments.types.clear();
1500 for (int i = 0; i < typeParameters.length; i++) {
1501 arguments.types.add(const DynamicType());
1502 }
1503 }
1504
1505 if (missingInitializers) {
1506 library.addArgumentsWithMissingDefaultValues(arguments, function);
1507 }
1508 return true;
1509 }
1510
1511 void handleNewExpression(Token token) {
1512 debugEvent("NewExpression");
1513 Arguments arguments = pop();
1514 String name = pop();
1515 List typeArguments = pop();
1516 var type = pop();
1517
1518 if (typeArguments != null) {
1519 assert(arguments.types.isEmpty);
1520 arguments.types.addAll(typeArguments);
1521 }
1522
1523 String errorName;
1524 if (type is ClassBuilder) {
1525 Builder b = type.findConstructorOrFactory(name);
1526 Member target;
1527 if (b == null) {
1528 // Not found. Reported below.
1529 } else if (b.isConstructor) {
1530 if (type.cls.isAbstract) {
1531 // TODO(ahe): Generate abstract instantiation error.
1532 } else {
1533 target = b.target;
1534 }
1535 } else if (b.isFactory) {
1536 target = getRedirectionTarget(b.target);
1537 if (target == null) {
1538 push(buildCompileTimeError(
1539 "Cyclic definition of factory '${name}'.",
1540 token.charOffset));
1541 return;
1542 }
1543 }
1544 if (target is Constructor ||
1545 (target is Procedure && target.kind == ProcedureKind.Factory)) {
1546 push(buildStaticInvocation(
1547 target, arguments, isConst: optional("const", token)));
1548 return;
1549 } else {
1550 errorName = debugName(type.cls.name, name);
1551 }
1552 } else {
1553 errorName = debugName(getNodeName(type), name);
1554 }
1555 errorName ??= name;
1556 push(throwNoSuchMethodError(errorName, arguments, token.charOffset));
1557 }
1558
1559 void handleConstExpression(Token token) {
1560 debugEvent("ConstExpression");
1561 handleNewExpression(token);
1562 }
1563
1564 void endTypeArguments(int count, Token beginToken, Token endToken) {
1565 debugEvent("TypeArguments");
1566 push(popList(count));
1567 }
1568
1569 void handleThisExpression(Token token) {
1570 debugEvent("ThisExpression");
1571 if (isFirstIdentifier && isInstanceContext) {
1572 push(new ThisAccessor(this, token.charOffset, inInitializer));
1573 } else {
1574 push(new IncompleteError(
1575 this, token.charOffset, "Expected identifier, but got 'this'."));
1576 }
1577 }
1578
1579 void handleSuperExpression(Token token) {
1580 debugEvent("SuperExpression");
1581 if (isFirstIdentifier && isInstanceContext) {
1582 Member member = this.member.target;
1583 member.transformerFlags |= TransformerFlag.superCalls;
1584 push(new ThisAccessor(this, token.charOffset, inInitializer,
1585 isSuper: true));
1586 } else {
1587 push(new IncompleteError(
1588 this, token.charOffset, "Expected identifier, but got 'super'."));
1589 }
1590 }
1591
1592 void handleNamedArgument(Token colon) {
1593 debugEvent("NamedArgument");
1594 Expression value = popForValue();
1595 Identifier identifier = pop();
1596 push(new NamedExpression(identifier.name, value));
1597 }
1598
1599 void endFunctionName(Token token) {
1600 debugEvent("FunctionName");
1601 Identifier name = pop();
1602 VariableDeclaration variable = new VariableDeclaration(
1603 name.name, isFinal: true);
1604 push(new FunctionDeclaration(variable,
1605 new FunctionNode(new InvalidStatement())));
1606 scope[variable.name] = new KernelVariableBuilder(variable);
1607 enterLocalScope();
1608 }
1609
1610 void beginFunction(Token token) {
1611 debugEvent("beginFunction");
1612 functionNestingLevel++;
1613 }
1614
1615 void beginUnnamedFunction(Token token) {
1616 debugEvent("beginUnnamedFunction");
1617 functionNestingLevel++;
1618 }
1619
1620 void endFunction(Token getOrSet, Token endToken) {
1621 debugEvent("Function");
1622 Statement body = popStatement();
1623 AsyncMarker asyncModifier = pop();
1624 if (functionNestingLevel != 0) {
1625 exitLocalScope();
1626 }
1627 FormalParameters formals = pop();
1628 List typeParameters = pop();
1629 push(formals.addToFunction(new FunctionNode(body,
1630 typeParameters: typeParameters, asyncMarker: asyncModifier)));
1631 functionNestingLevel--;
1632 }
1633
1634 void endFunctionDeclaration(Token token) {
1635 debugEvent("FunctionDeclaration");
1636 FunctionNode function = pop();
1637 exitLocalScope();
1638 FunctionDeclaration declaration = pop();
1639 function.returnType = pop() ?? const DynamicType();
1640 pop(); // Modifiers.
1641 declaration.function = function;
1642 function.parent = declaration;
1643 push(declaration);
1644 }
1645
1646 void endUnnamedFunction(Token token) {
1647 debugEvent("UnnamedFunction");
1648 Statement body = popStatement();
1649 AsyncMarker asyncModifier = pop();
1650 exitLocalScope();
1651 FormalParameters formals = pop();
1652 List typeParameters = pop();
1653 FunctionNode function = formals.addToFunction(new FunctionNode(body,
1654 typeParameters: typeParameters, asyncMarker: asyncModifier));
1655 push(new FunctionExpression(function));
1656 functionNestingLevel--;
1657 }
1658
1659 void endDoWhileStatement(
1660 Token doKeyword, Token whileKeyword, Token endToken) {
1661 debugEvent("DoWhileStatement");
1662 Expression condition = popForValue();
1663 Statement body = popStatement();
1664 JumpTarget continueTarget = exitContinueTarget();
1665 JumpTarget breakTarget = exitBreakTarget();
1666 if (continueTarget.hasUsers) {
1667 body = new LabeledStatement(body);
1668 continueTarget.resolveContinues(body);
1669 }
1670 Statement result = new DoStatement(body, condition);
1671 if (breakTarget.hasUsers) {
1672 result = new LabeledStatement(result);
1673 breakTarget.resolveBreaks(result);
1674 }
1675 exitLoopOrSwitch(result);
1676 }
1677
1678 void endForIn(
1679 Token awaitToken, Token forToken, Token inKeyword, Token endToken) {
1680 debugEvent("ForIn");
1681 Statement body = popStatement();
1682 Expression expression = popForValue();
1683 var lvalue = pop();
1684 exitLocalScope();
1685 JumpTarget continueTarget = exitContinueTarget();
1686 JumpTarget breakTarget = exitBreakTarget();
1687 if (continueTarget.hasUsers) {
1688 body = new LabeledStatement(body);
1689 continueTarget.resolveContinues(body);
1690 }
1691 VariableDeclaration variable;
1692 if (lvalue is VariableDeclaration) {
1693 variable = lvalue;
1694 } else if (lvalue is BuilderAccessor) {
1695 /// We are in this case, where `lvalue` isn't a [VariableDeclaration]:
1696 ///
1697 /// for (lvalue in expression) body
1698 ///
1699 /// This is normalized to:
1700 ///
1701 /// for (final #t in expression) {
1702 /// lvalue = #t;
1703 /// body;
1704 /// }
1705 variable = new VariableDeclaration.forValue(null);
1706 body = combineStatements(
1707 new ExpressionStatement(
1708 lvalue.buildAssignment(
1709 new VariableGet(variable), voidContext: true)),
1710 body);
1711 } else {
1712 throw inputError("Expected lvalue, but got ${lvalue}",
1713 forToken.next.next.charOffset);
1714 }
1715 Statement result = new ForInStatement(variable, expression, body,
1716 isAsync: awaitToken != null);
1717 if (breakTarget.hasUsers) {
1718 result = new LabeledStatement(result);
1719 breakTarget.resolveBreaks(result);
1720 }
1721 exitLoopOrSwitch(result);
1722 }
1723
1724 void handleLabel(Token token) {
1725 debugEvent("Label");
1726 Identifier identifier = pop();
1727 push(new Label(identifier.name));
1728 }
1729
1730 void beginLabeledStatement(Token token, int labelCount) {
1731 debugEvent("beginLabeledStatement");
1732 List<Label> labels = popList(labelCount);
1733 enterLocalScope();
1734 LabelTarget target = new LabelTarget();
1735 for (Label label in labels) {
1736 scope[label.name] = target;
1737 }
1738 push(target);
1739 }
1740
1741 void endLabeledStatement(int labelCount) {
1742 debugEvent("LabeledStatement");
1743 Statement statement = popStatement();
1744 LabelTarget target = pop();
1745 exitLocalScope();
1746 if (target.breakTarget.hasUsers) {
1747 if (statement is! LabeledStatement) {
1748 statement = new LabeledStatement(statement);
1749 }
1750 target.breakTarget.resolveBreaks(statement);
1751 }
1752 if (target.continueTarget.hasUsers) {
1753 if (statement is! LabeledStatement) {
1754 statement = new LabeledStatement(statement);
1755 }
1756 target.continueTarget.resolveContinues(statement);
1757 }
1758 push(statement);
1759 }
1760
1761 void endRethrowStatement(Token throwToken, Token endToken) {
1762 debugEvent("RethrowStatement");
1763 push(new ExpressionStatement(new Rethrow()));
1764 }
1765
1766 void handleFinallyBlock(Token finallyKeyword) {
1767 debugEvent("FinallyBlock");
1768 // Do nothing, handled by [endTryStatement].
1769 }
1770
1771 void endWhileStatement(Token whileKeyword, Token endToken) {
1772 debugEvent("WhileStatement");
1773 Statement body = popStatement();
1774 Expression condition = popForValue();
1775 JumpTarget continueTarget = exitContinueTarget();
1776 JumpTarget breakTarget = exitBreakTarget();
1777 if (continueTarget.hasUsers) {
1778 body = new LabeledStatement(body);
1779 continueTarget.resolveContinues(body);
1780 }
1781 Statement result = new WhileStatement(condition, body);
1782 if (breakTarget.hasUsers) {
1783 result = new LabeledStatement(result);
1784 breakTarget.resolveBreaks(result);
1785 }
1786 exitLoopOrSwitch(result);
1787 }
1788
1789 void handleEmptyStatement(Token token) {
1790 debugEvent("EmptyStatement");
1791 push(new EmptyStatement());
1792 }
1793
1794 void handleAssertStatement(
1795 Token assertKeyword, Token commaToken, Token semicolonToken) {
1796 debugEvent("AssertStatement");
1797 Expression message = popIfNotNull(commaToken);
1798 Expression condition = popForValue();
1799 push(new AssertStatement(condition, message));
1800 }
1801
1802 void endYieldStatement(Token yieldToken, Token starToken, Token endToken) {
1803 debugEvent("YieldStatement");
1804 push(new YieldStatement(popForValue(), isYieldStar: starToken != null));
1805 }
1806
1807 void beginSwitchBlock(Token token) {
1808 debugEvent("beginSwitchBlock");
1809 enterLocalScope();
1810 enterSwitchScope();
1811 enterBreakTarget();
1812 }
1813
1814 void beginSwitchCase(int labelCount, int expressionCount, Token firstToken) {
1815 debugEvent("beginSwitchCase");
1816 List labelsAndExpressions = popList(labelCount + expressionCount);
1817 List<Label> labels = <Label>[];
1818 List<Expression> expressions = <Expression>[];
1819 if (labelsAndExpressions != null) {
1820 for (var labelOrExpression in labelsAndExpressions) {
1821 if (labelOrExpression is Label) {
1822 labels.add(labelOrExpression);
1823 } else {
1824 expressions.add(toValue(labelOrExpression));
1825 }
1826 }
1827 }
1828 assert(scope == switchScope);
1829 for (Label label in labels) {
1830 Builder existing = scope.local[label.name];
1831 if (existing == null) {
1832 scope[label.name] = createGotoTarget();
1833 } else {
1834 // TODO(ahe): Should validate this is a goto target and not duplicated.
1835 }
1836 }
1837 push(expressions);
1838 push(labels);
1839 enterLocalScope();
1840 }
1841
1842 void handleSwitchCase(
1843 int labelCount,
1844 int expressionCount,
1845 Token defaultKeyword,
1846 int statementCount,
1847 Token firstToken,
1848 Token endToken) {
1849 debugEvent("SwitchCase");
1850 Block block = popBlock(statementCount);
1851 exitLocalScope();
1852 List<Label> labels = pop();
1853 List<Expression> expressions = pop();
1854 push(new SwitchCase(expressions, block, isDefault: defaultKeyword != null));
1855 push(labels);
1856 }
1857
1858 void endSwitchStatement(Token switchKeyword, Token endToken) {
1859 debugEvent("SwitchStatement");
1860 // Do nothing. Handled by [endSwitchBlock].
1861 }
1862
1863 void endSwitchBlock(int caseCount, Token beginToken, Token endToken) {
1864 debugEvent("SwitchBlock");
1865 List<SwitchCase> cases =
1866 new List<SwitchCase>.filled(caseCount, null, growable: true);
1867 for (int i = caseCount - 1; i >= 0; i--) {
1868 List<Label> labels = pop();
1869 SwitchCase current = cases[i] = pop();
1870 for (Label label in labels) {
1871 JumpTarget target = switchScope.lookup(label.name);
1872 if (target != null) {
1873 target.resolveGotos(current);
1874 }
1875 }
1876 // TODO(ahe): Validate that there's only one default and it's last.
1877 }
1878 JumpTarget target = exitBreakTarget();
1879 exitSwitchScope();
1880 exitLocalScope();
1881 Expression expression = popForValue();
1882 Statement result = new SwitchStatement(expression, cases);
1883 if (target.hasUsers) {
1884 result = new LabeledStatement(result);
1885 target.resolveBreaks(result);
1886 }
1887 exitLoopOrSwitch(result);
1888 }
1889
1890 void handleCaseMatch(Token caseKeyword, Token colon) {
1891 debugEvent("CaseMatch");
1892 // Do nothing. Handled by [handleSwitchCase].
1893 }
1894
1895 void handleBreakStatement(
1896 bool hasTarget, Token breakKeyword, Token endToken) {
1897 debugEvent("BreakStatement");
1898 var target = breakTarget;
1899 String name;
1900 if (hasTarget) {
1901 Identifier identifier = pop();
1902 name = identifier.name;
1903 target = scope.lookup(identifier.name);
1904 }
1905 if (target == null && name == null) {
1906 push(compileTimeErrorInLoopOrSwitch =
1907 buildCompileTimeErrorStatement(
1908 "No target of break.", breakKeyword.charOffset));
1909 } else if (target == null || target is! JumpTarget
1910 || !target.isBreakTarget) {
1911 push(compileTimeErrorInLoopOrSwitch =
1912 buildCompileTimeErrorStatement("Can't break to '$name'.",
1913 breakKeyword.next.charOffset));
1914 } else {
1915 BreakStatement statement = new BreakStatement(null);
1916 target.addBreak(statement);
1917 push(statement);
1918 }
1919 }
1920
1921 void handleContinueStatement(
1922 bool hasTarget, Token continueKeyword, Token endToken) {
1923 debugEvent("ContinueStatement");
1924 var target = continueTarget;
1925 String name;
1926 if (hasTarget) {
1927 Identifier identifier = pop();
1928 name = identifier.name;
1929 target = scope.lookup(identifier.name);
1930 if (target != null && target is! JumpTarget) {
1931 push(compileTimeErrorInLoopOrSwitch =
1932 buildCompileTimeErrorStatement(
1933 "Target of continue must be a label.",
1934 continueKeyword.charOffset));
1935 return;
1936 }
1937 if (target == null) {
1938 if (switchScope == null) {
1939 push(buildCompileTimeErrorStatement("Can't find label '$name'.",
1940 continueKeyword.next.charOffset));
1941 return;
1942 }
1943 switchScope[identifier.name] = target = createGotoTarget();
1944 }
1945 if (target.isGotoTarget) {
1946 ContinueSwitchStatement statement = new ContinueSwitchStatement(null);
1947 target.addGoto(statement);
1948 push(statement);
1949 return;
1950 }
1951 }
1952 if (target == null) {
1953 push(compileTimeErrorInLoopOrSwitch =
1954 buildCompileTimeErrorStatement("No target of continue.",
1955 continueKeyword.charOffset));
1956 } else if (!target.isContinueTarget) {
1957 push(compileTimeErrorInLoopOrSwitch =
1958 buildCompileTimeErrorStatement("Can't continue at '$name'.",
1959 continueKeyword.next.charOffset));
1960 } else {
1961 BreakStatement statement = new BreakStatement(null);
1962 target.addContinue(statement);
1963 push(statement);
1964 }
1965 }
1966
1967 void endTypeVariable(Token token, Token extendsOrSuper) {
1968 logEvent("TypeVariable");
1969 // TODO(ahe): Implement this when enabling generic method syntax.
1970 }
1971
1972 void endTypeVariables(int count, Token beginToken, Token endToken) {
1973 logEvent("TypeVariables");
1974 // TODO(ahe): Implement this when enabling generic method syntax.
1975 }
1976
1977 void handleModifier(Token token) {
1978 debugEvent("Modifier");
1979 // TODO(ahe): Copied from outline_builder.dart.
1980 push(new Modifier.fromString(token.stringValue));
1981 }
1982
1983 void handleModifiers(int count) {
1984 debugEvent("Modifiers");
1985 // TODO(ahe): Copied from outline_builder.dart.
1986 push(popList(count) ?? NullValue.Modifiers);
1987 }
1988
1989 void reportErrorHelper(Token token, ErrorKind kind, Map arguments) {
1990 super.reportErrorHelper(token, kind, arguments);
1991 if (!hasParserError) {
1992 print("$uri:${recoverableErrors.last}");
1993 }
1994 hasParserError = true;
1995 }
1996
1997 Token expectedExpression(Token token) {
1998 if (token is ErrorToken) {
1999 reportErrorToken(token);
2000 push(new Throw(new StringLiteral("${recoverableErrors.last}")));
2001 do {
2002 token = token.next;
2003 } while (token is ErrorToken);
2004 return token;
2005 } else {
2006 push(new InvalidExpression());
2007 return super.expectedExpression(token);
2008 }
2009 }
2010
2011 Token expected(String string, Token token) {
2012 if (token is ErrorToken) {
2013 reportErrorToken(token);
2014 do {
2015 token = token.next;
2016 } while (token is ErrorToken);
2017 return token;
2018 }
2019 const List<String> trailing = const <String>[")", "}", ";", ","];
2020 if (trailing.contains(token.stringValue) && trailing.contains(string)) {
2021 // We're just trying to get out an error.
2022 if (recoverableErrors.isNotEmpty) {
2023 reportError(token, ErrorKind.UNSPECIFIED,
2024 {"text": "Expected: '$string', but got '${token.value}'"});
2025 }
2026 return token;
2027 }
2028 return super.expected(string, token);
2029 }
2030
2031 void warning(error, [int charOffset = -1]) {
2032 String message = new InputError(uri, charOffset, error).format();
2033 print(message);
2034 }
2035
2036 void nit(error, [int charOffset = -1]) {
2037 if (!showNits) return;
2038 String message = new InputError(uri, charOffset, error).format();
2039 print(message);
2040 }
2041
2042 Expression buildCompileTimeError(error, [int charOffset = -1]) {
2043 String message = new InputError(uri, charOffset, error).format();
2044 print(message);
2045 return new Throw(new StringLiteral(message));
2046 }
2047
2048 Statement buildCompileTimeErrorStatement(error, [int charOffset = -1]) {
2049 return new ExpressionStatement(buildCompileTimeError(error, charOffset));
2050 }
2051
2052 Initializer buildCompileTimeErrorIntializer(error, [int charOffset = -1]) {
2053 return new LocalInitializer(
2054 new VariableDeclaration.forValue(
2055 buildCompileTimeError(error, charOffset)));
2056 }
2057
2058
2059 Expression buildProblemExpression(Builder builder, String name) {
2060 if (builder is AmbiguousBuilder) {
2061 return buildCompileTimeError("Duplicated named: '$name'.");
2062 } else if (builder is AccessErrorBuilder) {
2063 return buildCompileTimeError("Access error: '$name'.");
2064 } else {
2065 return internalError("Unhandled: ${builder.runtimeType}");
2066 }
2067 }
2068
2069 void handleOperator(Token token) {
2070 debugEvent("Operator");
2071 push(new Operator(token.stringValue)..fileOffset = token.charOffset);
2072 }
2073
2074 dynamic inputError(String message, [int charOffset = -1]) {
2075 return errors.inputError(uri, charOffset, message);
2076 }
2077
2078 void debugEvent(String name) {
2079 // printEvent(name);
2080 }
2081 }
2082
2083 // TODO(ahe): Shouldn't need to be an expression.
2084 class UnresolvedIdentifier extends InvalidExpression {
2085 final Name name;
2086
2087 UnresolvedIdentifier(this.name);
2088
2089 String toString() => "unresolved-identifier($name)";
2090 }
2091
2092 // TODO(ahe): Shouldn't need to be an expression.
2093 class Identifier extends InvalidExpression {
2094 final String name;
2095
2096 Identifier(this.name);
2097
2098 Expression get initializer => null;
2099
2100 String toString() => "identifier($name)";
2101 }
2102
2103 // TODO(ahe): Shouldn't need to be an expression.
2104 class Operator extends InvalidExpression {
2105 final String name;
2106
2107 Operator(this.name);
2108
2109 String toString() => "operator($name)";
2110 }
2111
2112 class InitializedIdentifier extends Identifier {
2113 final Expression initializer;
2114
2115 InitializedIdentifier(String name, this.initializer)
2116 : super(name);
2117
2118 String toString() => "initialized-identifier($name, $initializer)";
2119 }
2120
2121 // TODO(ahe): Shouldn't need to be an expression.
2122 class Label extends InvalidExpression {
2123 String name;
2124
2125 Label(this.name);
2126
2127 String toString() => "label($name)";
2128 }
2129
2130 class CascadeReceiver extends Let {
2131 Let nextCascade;
2132
2133 CascadeReceiver(VariableDeclaration variable)
2134 : super(variable,
2135 makeLet(new VariableDeclaration.forValue(new InvalidExpression()),
2136 new VariableGet(variable))) {
2137 nextCascade = body;
2138 }
2139
2140 void extend() {
2141 assert(nextCascade.variable.initializer is! InvalidExpression);
2142 Let newCascade = makeLet(
2143 new VariableDeclaration.forValue(new InvalidExpression()),
2144 nextCascade.body);
2145 nextCascade.body = newCascade;
2146 newCascade.parent = nextCascade;
2147 nextCascade = newCascade;
2148 }
2149
2150 void finalize(Expression expression) {
2151 assert(nextCascade.variable.initializer is InvalidExpression);
2152 nextCascade.variable.initializer = expression;
2153 expression.parent = nextCascade.variable;
2154 }
2155 }
2156
2157 abstract class ContextAccessor extends BuilderAccessor {
2158 final BuilderHelper helper;
2159
2160 final int charOffset;
2161
2162 final BuilderAccessor accessor;
2163
2164 ContextAccessor(this.helper, this.charOffset, this.accessor);
2165
2166 String get plainNameForRead => internalError("Unsupported operation.");
2167
2168 Expression doInvocation(int charOffset, Arguments arguments) {
2169 print("$uri:$charOffset: Internal error: Unhandled: ${runtimeType}");
2170 return internalError("Unhandled: ${runtimeType}");
2171 }
2172
2173 Expression buildSimpleRead();
2174
2175 Expression buildForEffect();
2176
2177 Expression buildAssignment(Expression value, {bool voidContext: false}) {
2178 return internalError("not supported");
2179 }
2180
2181 Expression buildNullAwareAssignment(Expression value, DartType type,
2182 {bool voidContext: false}) {
2183 return internalError("not supported");
2184 }
2185
2186 Expression buildCompoundAssignment(Name binaryOperator, Expression value,
2187 {bool voidContext: false, Procedure interfaceTarget}) {
2188 return internalError("not supported");
2189 }
2190
2191 Expression buildPrefixIncrement(Name binaryOperator,
2192 {bool voidContext: false, Procedure interfaceTarget}) {
2193 return internalError("not supported");
2194 }
2195
2196 Expression buildPostfixIncrement(Name binaryOperator,
2197 {bool voidContext: false, Procedure interfaceTarget}) {
2198 return internalError("not supported");
2199 }
2200
2201 makeInvalidRead() => internalError("not supported");
2202
2203 makeInvalidWrite(Expression value) => internalError("not supported");
2204 }
2205
2206 class DelayedAssignment extends ContextAccessor {
2207 final Expression value;
2208
2209 final String assignmentOperator;
2210
2211 DelayedAssignment(BuilderHelper helper, int charOffset,
2212 BuilderAccessor accessor, this.value, this.assignmentOperator)
2213 : super(helper, charOffset, accessor);
2214
2215 Expression buildSimpleRead() {
2216 return handleAssignment(false);
2217 }
2218
2219 Expression buildForEffect() {
2220 return handleAssignment(true);
2221 }
2222
2223 Expression handleAssignment(bool voidContext) {
2224 if (identical("=", assignmentOperator)) {
2225 return accessor.buildAssignment(value, voidContext: voidContext);
2226 } else if (identical("+=", assignmentOperator)) {
2227 return accessor.buildCompoundAssignment(
2228 plusName, value, voidContext: voidContext);
2229 } else if (identical("-=", assignmentOperator)) {
2230 return accessor.buildCompoundAssignment(
2231 minusName, value, voidContext: voidContext);
2232 } else if (identical("*=", assignmentOperator)) {
2233 return accessor.buildCompoundAssignment(
2234 multiplyName, value, voidContext: voidContext);
2235 } else if (identical("%=", assignmentOperator)) {
2236 return accessor.buildCompoundAssignment(
2237 percentName, value, voidContext: voidContext);
2238 } else if (identical("&=", assignmentOperator)) {
2239 return accessor.buildCompoundAssignment(
2240 ampersandName, value, voidContext: voidContext);
2241 } else if (identical("/=", assignmentOperator)) {
2242 return accessor.buildCompoundAssignment(
2243 divisionName, value, voidContext: voidContext);
2244 } else if (identical("<<=", assignmentOperator)) {
2245 return accessor.buildCompoundAssignment(
2246 leftShiftName, value, voidContext: voidContext);
2247 } else if (identical(">>=", assignmentOperator)) {
2248 return accessor.buildCompoundAssignment(
2249 rightShiftName, value, voidContext: voidContext);
2250 } else if (identical("??=", assignmentOperator)) {
2251 return accessor.buildNullAwareAssignment(
2252 value, const DynamicType(), voidContext: voidContext);
2253 } else if (identical("^=", assignmentOperator)) {
2254 return accessor.buildCompoundAssignment(
2255 caretName, value, voidContext: voidContext);
2256 } else if (identical("|=", assignmentOperator)) {
2257 return accessor.buildCompoundAssignment(
2258 barName, value, voidContext: voidContext);
2259 } else if (identical("~/=", assignmentOperator)) {
2260 return accessor.buildCompoundAssignment(
2261 mustacheName, value, voidContext: voidContext);
2262 } else {
2263 return internalError("Unhandled: $assignmentOperator");
2264 }
2265 }
2266
2267 Initializer buildFieldInitializer(
2268 Map<String, FieldInitializer> initializers) {
2269 if (!identical("=", assignmentOperator) ||
2270 !accessor.isThisPropertyAccessor) {
2271 return accessor.buildFieldInitializer(initializers);
2272 }
2273 String name = accessor.plainNameForRead;
2274 FieldInitializer initializer = initializers[name];
2275 if (initializer != null && initializer.value == null) {
2276 initializers.remove(name);
2277 initializer.value = value
2278 ..parent = initializer;
2279 return initializer;
2280 }
2281 return accessor.buildFieldInitializer(initializers);
2282 }
2283 }
2284
2285 class DelayedPostfixIncrement extends ContextAccessor {
2286 final Name binaryOperator;
2287
2288 final Procedure interfaceTarget;
2289
2290 DelayedPostfixIncrement(BuilderHelper helper, int charOffset,
2291 BuilderAccessor accessor, this.binaryOperator, this.interfaceTarget)
2292 : super(helper, charOffset, accessor);
2293
2294 Expression buildSimpleRead() {
2295 return accessor.buildPostfixIncrement(binaryOperator, voidContext: false,
2296 interfaceTarget: interfaceTarget);
2297 }
2298
2299 Expression buildForEffect() {
2300 return accessor.buildPostfixIncrement(binaryOperator, voidContext: true,
2301 interfaceTarget: interfaceTarget);
2302 }
2303 }
2304
2305 class JumpTarget extends Builder {
2306 final List<Statement> users = <Statement>[];
2307
2308 final JumpTargetKind kind;
2309
2310 JumpTarget(this.kind);
2311
2312 bool get isBreakTarget => kind == JumpTargetKind.Break;
2313
2314 bool get isContinueTarget => kind == JumpTargetKind.Continue;
2315
2316 bool get isGotoTarget => kind == JumpTargetKind.Goto;
2317
2318 bool get hasUsers => users.isNotEmpty;
2319
2320 void addBreak(BreakStatement statement) {
2321 assert(isBreakTarget);
2322 users.add(statement);
2323 }
2324
2325 void addContinue(BreakStatement statement) {
2326 assert(isContinueTarget);
2327 users.add(statement);
2328 }
2329
2330 void addGoto(ContinueSwitchStatement statement) {
2331 assert(isGotoTarget);
2332 users.add(statement);
2333 }
2334
2335 void resolveBreaks(LabeledStatement target) {
2336 assert(isBreakTarget);
2337 for (BreakStatement user in users) {
2338 user.target = target;
2339 }
2340 users.clear();
2341 }
2342
2343 void resolveContinues(LabeledStatement target) {
2344 assert(isContinueTarget);
2345 for (BreakStatement user in users) {
2346 user.target = target;
2347 }
2348 users.clear();
2349 }
2350
2351 void resolveGotos(SwitchCase target) {
2352 assert(isGotoTarget);
2353 for (ContinueSwitchStatement user in users) {
2354 user.target = target;
2355 }
2356 users.clear();
2357 }
2358 }
2359
2360 class LabelTarget extends Builder implements JumpTarget {
2361 final JumpTarget breakTarget = new JumpTarget(JumpTargetKind.Break);
2362
2363 final JumpTarget continueTarget = new JumpTarget(JumpTargetKind.Continue);
2364
2365 LabelTarget();
2366
2367 bool get hasUsers => breakTarget.hasUsers || continueTarget.hasUsers;
2368
2369 List<Statement> get users => internalError("Unsupported operation.");
2370
2371 JumpTargetKind get kind => internalError("Unsupported operation.");
2372
2373 bool get isBreakTarget => true;
2374
2375 bool get isContinueTarget => true;
2376
2377 bool get isGotoTarget => false;
2378
2379 void addBreak(BreakStatement statement) {
2380 breakTarget.addBreak(statement);
2381 }
2382
2383 void addContinue(BreakStatement statement) {
2384 continueTarget.addContinue(statement);
2385 }
2386
2387 void addGoto(ContinueSwitchStatement statement) {
2388 internalError("Unsupported operation.");
2389 }
2390
2391 void resolveBreaks(LabeledStatement target) {
2392 breakTarget.resolveBreaks(target);
2393 }
2394
2395 void resolveContinues(LabeledStatement target) {
2396 continueTarget.resolveContinues(target);
2397 }
2398
2399 void resolveGotos(SwitchCase target) {
2400 internalError("Unsupported operation.");
2401 }
2402 }
2403
2404 class OptionalFormals {
2405 final FormalParameterType kind;
2406
2407 final List<VariableDeclaration> formals;
2408
2409 OptionalFormals(this.kind, this.formals);
2410 }
2411
2412 class FormalParameters {
2413 final List<VariableDeclaration> required;
2414 final OptionalFormals optional;
2415
2416 FormalParameters(this.required, this.optional);
2417
2418 FunctionNode addToFunction(FunctionNode function) {
2419 function.requiredParameterCount = required.length;
2420 function.positionalParameters.addAll(required);
2421 if (optional != null) {
2422 if (optional.kind.isPositional) {
2423 function.positionalParameters.addAll(optional.formals);
2424 } else {
2425 function.namedParameters.addAll(optional.formals);
2426 setParents(function.namedParameters, function);
2427 }
2428 }
2429 setParents(function.positionalParameters, function);
2430 return function;
2431 }
2432
2433 FunctionType toFunctionType(DartType returnType) {
2434 returnType ??= const DynamicType();
2435 int requiredParameterCount = required.length;
2436 List<DartType> positionalParameters = <DartType>[];
2437 List<NamedType> namedParameters = const <NamedType>[];
2438 for (VariableDeclaration parameter in required) {
2439 positionalParameters.add(parameter.type);
2440 }
2441 if (optional != null) {
2442 if (optional.kind.isPositional) {
2443 for (VariableDeclaration parameter in optional.formals) {
2444 positionalParameters.add(parameter.type);
2445 }
2446 } else {
2447 namedParameters = <NamedType>[];
2448 for (VariableDeclaration parameter in optional.formals) {
2449 namedParameters.add(new NamedType(parameter.name, parameter.type));
2450 }
2451 namedParameters.sort();
2452 }
2453 }
2454 return new FunctionType(positionalParameters, returnType,
2455 namedParameters: namedParameters,
2456 requiredParameterCount: requiredParameterCount);
2457 }
2458
2459 Scope computeFormalParameterScope(Scope parent) {
2460 if (required.length == 0 && optional == null) return parent;
2461 Map<String, Builder> local = <String, Builder>{};
2462 for (VariableDeclaration parameter in required) {
2463 local[parameter.name] = new KernelVariableBuilder(parameter);
2464 }
2465 if (optional != null) {
2466 for (VariableDeclaration parameter in optional.formals) {
2467 local[parameter.name] = new KernelVariableBuilder(parameter);
2468 }
2469 }
2470 return new Scope(local, parent, isModifiable: false);
2471 }
2472 }
2473
2474 /// Returns a block like this:
2475 ///
2476 /// {
2477 /// statement;
2478 /// body;
2479 /// }
2480 ///
2481 /// If [body] is a [Block], it's returned with [statement] prepended to it.
2482 Block combineStatements(Statement statement, Statement body) {
2483 if (body is Block) {
2484 body.statements.insert(0, statement);
2485 statement.parent = body;
2486 return body;
2487 } else {
2488 return new Block(<Statement>[statement, body]);
2489 }
2490 }
2491
2492 String debugName(String className, String name, [String prefix]) {
2493 String result = name.isEmpty ? className : "$className.$name";
2494 return prefix == null ? result : "$prefix.result";
2495 }
2496
2497 String getNodeName(Object node) {
2498 if (node is Identifier) {
2499 return node.name;
2500 } else if (node is UnresolvedIdentifier) {
2501 return node.name.name;
2502 } else if (node is TypeDeclarationBuilder) {
2503 return node.name;
2504 } else if (node is PrefixBuilder) {
2505 return node.name;
2506 } else if (node is ThisPropertyAccessor) {
2507 return node.name.name;
2508 } else {
2509 return internalError("Unhandled: ${node.runtimeType}");
2510 }
2511 }
OLDNEW
« no previous file with comments | « no previous file | pkg/fasta/lib/src/kernel/builder_accessors.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698