OLD | NEW |
---|---|
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library fasta.body_builder; | 5 library fasta.body_builder; |
6 | 6 |
7 import '../fasta_codes.dart' | 7 import '../fasta_codes.dart' |
8 show FastaMessage, codeExpectedButGot, codeExpectedFunctionBody; | 8 show FastaMessage, codeExpectedButGot, codeExpectedFunctionBody; |
9 | 9 |
10 import '../parser/parser.dart' show FormalParameterType, MemberKind, optional; | 10 import '../parser/parser.dart' show FormalParameterType, MemberKind, optional; |
(...skipping 2463 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2474 void beginSwitchCase(int labelCount, int expressionCount, Token firstToken) { | 2474 void beginSwitchCase(int labelCount, int expressionCount, Token firstToken) { |
2475 debugEvent("beginSwitchCase"); | 2475 debugEvent("beginSwitchCase"); |
2476 List labelsAndExpressions = popList(labelCount + expressionCount); | 2476 List labelsAndExpressions = popList(labelCount + expressionCount); |
2477 List<Label> labels = <Label>[]; | 2477 List<Label> labels = <Label>[]; |
2478 List<Expression> expressions = <Expression>[]; | 2478 List<Expression> expressions = <Expression>[]; |
2479 if (labelsAndExpressions != null) { | 2479 if (labelsAndExpressions != null) { |
2480 for (var labelOrExpression in labelsAndExpressions) { | 2480 for (var labelOrExpression in labelsAndExpressions) { |
2481 if (labelOrExpression is Label) { | 2481 if (labelOrExpression is Label) { |
2482 labels.add(labelOrExpression); | 2482 labels.add(labelOrExpression); |
2483 } else { | 2483 } else { |
2484 expressions.add(toValue(labelOrExpression)); | 2484 expressions.add(labelOrExpression); |
2485 } | 2485 } |
2486 } | 2486 } |
2487 } | 2487 } |
2488 assert(scope == switchScope); | 2488 assert(scope == switchScope); |
2489 for (Label label in labels) { | 2489 for (Label label in labels) { |
2490 if (scope.hasLocalLabel(label.name)) { | 2490 if (scope.hasLocalLabel(label.name)) { |
2491 // TODO(ahe): Should validate this is a goto target and not duplicated. | 2491 // TODO(ahe): Should validate this is a goto target and not duplicated. |
2492 scope.claimLabel(label.name); | 2492 scope.claimLabel(label.name); |
2493 } else { | 2493 } else { |
2494 scope.declareLabel(label.name, createGotoTarget(firstToken.charOffset)); | 2494 scope.declareLabel(label.name, createGotoTarget(firstToken.charOffset)); |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2535 new List<SwitchCase>.filled(caseCount, null, growable: true); | 2535 new List<SwitchCase>.filled(caseCount, null, growable: true); |
2536 for (int i = caseCount - 1; i >= 0; i--) { | 2536 for (int i = caseCount - 1; i >= 0; i--) { |
2537 List<Label> labels = pop(); | 2537 List<Label> labels = pop(); |
2538 SwitchCase current = cases[i] = pop(); | 2538 SwitchCase current = cases[i] = pop(); |
2539 for (Label label in labels) { | 2539 for (Label label in labels) { |
2540 JumpTarget target = switchScope.lookupLabel(label.name); | 2540 JumpTarget target = switchScope.lookupLabel(label.name); |
2541 if (target != null) { | 2541 if (target != null) { |
2542 target.resolveGotos(current); | 2542 target.resolveGotos(current); |
2543 } | 2543 } |
2544 } | 2544 } |
2545 // TODO(ahe): Validate that there's only one default and it's last. | 2545 } |
2546 // Check all but the last case for the following: | |
2547 // 1. That it isn't a default case (which should be last). | |
2548 // 2. That it doesn't fall through to the next case. | |
2549 for (int i = 0; i < caseCount - 1; i++) { | |
2550 SwitchCase current = cases[i]; | |
2551 if (current.isDefault) { | |
2552 addCompileTimeError(current.fileOffset, | |
2553 "'default' switch case should be the last case."); | |
2554 continue; | |
2555 } | |
2556 Block block = current.body; | |
2557 TreeNode lastNode = block; | |
2558 while (lastNode is Block || lastNode is LabeledStatement) { | |
Paul Berry
2017/06/06 18:32:26
This isn't consistent with the spec. The spec say
ahe
2017/06/06 18:40:05
Then I should replace lines 2558-2569 with lines 2
Paul Berry
2017/06/06 18:55:37
I think we still need the LabeledStatement logic.
ahe
2017/06/06 19:02:15
That's what I thought at first. However, that does
Paul Berry
2017/06/06 19:18:08
Fair enough. I've checked and analyzer's interpre
| |
2559 if (lastNode is Block) { | |
2560 Block block = lastNode; | |
2561 if (block.statements.isEmpty) { | |
2562 lastNode = null; | |
2563 } else { | |
2564 lastNode = block.statements.last; | |
2565 } | |
2566 } else if (lastNode is LabeledStatement) { | |
2567 LabeledStatement statement = lastNode; | |
2568 lastNode = statement.body; | |
2569 } | |
2570 } | |
2571 if (lastNode is ExpressionStatement) { | |
2572 ExpressionStatement statement = lastNode; | |
2573 lastNode = statement.expression; | |
2574 } | |
2575 if (lastNode is! BreakStatement && | |
2576 lastNode is! ContinueSwitchStatement && | |
2577 lastNode is! Rethrow && | |
2578 lastNode is! ReturnStatement && | |
2579 lastNode is! Throw) { | |
2580 block.addStatement( | |
2581 new ExpressionStatement(buildFallThroughError(current.fileOffset))); | |
2582 } | |
2546 } | 2583 } |
2547 JumpTarget target = exitBreakTarget(); | 2584 JumpTarget target = exitBreakTarget(); |
2548 exitSwitchScope(); | 2585 exitSwitchScope(); |
2549 exitLocalScope(); | 2586 exitLocalScope(); |
2550 Expression expression = popForValue(); | 2587 Expression expression = popForValue(); |
2551 Statement result = new SwitchStatement(expression, cases); | 2588 Statement result = new SwitchStatement(expression, cases); |
2552 if (target.hasUsers) { | 2589 if (target.hasUsers) { |
2553 result = new LabeledStatement(result); | 2590 result = new LabeledStatement(result); |
2554 target.resolveBreaks(result); | 2591 target.resolveBreaks(result); |
2555 } | 2592 } |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2710 } | 2747 } |
2711 | 2748 |
2712 Expression wrapInCompileTimeError(Expression expression, String message) { | 2749 Expression wrapInCompileTimeError(Expression expression, String message) { |
2713 return new Let( | 2750 return new Let( |
2714 new VariableDeclaration.forValue(expression) | 2751 new VariableDeclaration.forValue(expression) |
2715 ..fileOffset = expression.fileOffset, | 2752 ..fileOffset = expression.fileOffset, |
2716 buildCompileTimeError(message, expression.fileOffset)) | 2753 buildCompileTimeError(message, expression.fileOffset)) |
2717 ..fileOffset = expression.fileOffset; | 2754 ..fileOffset = expression.fileOffset; |
2718 } | 2755 } |
2719 | 2756 |
2757 Expression buildFallThroughError(int charOffset) { | |
2758 warningNotError("Switch case may fall through to next case.", charOffset); | |
2759 Builder constructor = library.loader.getFallThroughError(); | |
2760 return new Throw(buildStaticInvocation( | |
2761 constructor.target, new Arguments.empty(), | |
2762 charOffset: charOffset)); | |
2763 } | |
2764 | |
2720 Expression buildAbstractClassInstantiationError(String className, | 2765 Expression buildAbstractClassInstantiationError(String className, |
2721 [int charOffset = -1]) { | 2766 [int charOffset = -1]) { |
2722 warning("The class '$className' is abstract and can't be instantiated.", | 2767 warning("The class '$className' is abstract and can't be instantiated.", |
2723 charOffset); | 2768 charOffset); |
2724 Builder constructor = library.loader.getAbstractClassInstantiationError(); | 2769 Builder constructor = library.loader.getAbstractClassInstantiationError(); |
2725 return new Throw(buildStaticInvocation(constructor.target, | 2770 return new Throw(buildStaticInvocation(constructor.target, |
2726 new KernelArguments(<Expression>[new StringLiteral(className)]))); | 2771 new KernelArguments(<Expression>[new StringLiteral(className)]))); |
2727 } | 2772 } |
2728 | 2773 |
2729 Statement buildCompileTimeErrorStatement(error, [int charOffset = -1]) { | 2774 Statement buildCompileTimeErrorStatement(error, [int charOffset = -1]) { |
(...skipping 644 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3374 if (starToken == null) { | 3419 if (starToken == null) { |
3375 return AsyncMarker.Async; | 3420 return AsyncMarker.Async; |
3376 } else { | 3421 } else { |
3377 assert(identical(starToken.stringValue, "*")); | 3422 assert(identical(starToken.stringValue, "*")); |
3378 return AsyncMarker.AsyncStar; | 3423 return AsyncMarker.AsyncStar; |
3379 } | 3424 } |
3380 } else { | 3425 } else { |
3381 return internalError("Unknown async modifier: $asyncToken"); | 3426 return internalError("Unknown async modifier: $asyncToken"); |
3382 } | 3427 } |
3383 } | 3428 } |
OLD | NEW |