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

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

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

Powered by Google App Engine
This is Rietveld 408576698