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

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

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