Chromium Code Reviews| 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 |