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)); |
2495 } | 2495 } |
2496 } | 2496 } |
2497 push(expressions); | 2497 push(expressions); |
2498 push(labels); | 2498 push(labels); |
2499 enterLocalScope(); | 2499 enterLocalScope(); |
2500 } | 2500 } |
2501 | 2501 |
2502 @override | 2502 @override |
2503 void handleSwitchCase( | 2503 void handleSwitchCase( |
2504 int labelCount, | 2504 int labelCount, |
2505 int expressionCount, | 2505 int expressionCount, |
2506 Token defaultKeyword, | 2506 Token defaultKeyword, |
2507 int statementCount, | 2507 int statementCount, |
2508 Token firstToken, | 2508 Token firstToken, |
2509 Token endToken) { | 2509 Token endToken) { |
2510 debugEvent("SwitchCase"); | 2510 debugEvent("SwitchCase"); |
| 2511 // We always create a block here so that we later know that there's always |
| 2512 // one synthetic block when we finish compiling the switch statement and |
| 2513 // check this switch case to see if it falls through to the next case. |
2511 Block block = popBlock(statementCount, firstToken); | 2514 Block block = popBlock(statementCount, firstToken); |
2512 exitLocalScope(); | 2515 exitLocalScope(); |
2513 List<Label> labels = pop(); | 2516 List<Label> labels = pop(); |
2514 List<Expression> expressions = pop(); | 2517 List<Expression> expressions = pop(); |
2515 List<int> expressionOffsets = <int>[]; | 2518 List<int> expressionOffsets = <int>[]; |
2516 for (Expression expression in expressions) { | 2519 for (Expression expression in expressions) { |
2517 expressionOffsets.add(expression.fileOffset); | 2520 expressionOffsets.add(expression.fileOffset); |
2518 } | 2521 } |
2519 push(new SwitchCase(expressions, expressionOffsets, block, | 2522 push(new SwitchCase(expressions, expressionOffsets, block, |
2520 isDefault: defaultKeyword != null) | 2523 isDefault: defaultKeyword != null) |
(...skipping 14 matching lines...) Expand all Loading... |
2535 new List<SwitchCase>.filled(caseCount, null, growable: true); | 2538 new List<SwitchCase>.filled(caseCount, null, growable: true); |
2536 for (int i = caseCount - 1; i >= 0; i--) { | 2539 for (int i = caseCount - 1; i >= 0; i--) { |
2537 List<Label> labels = pop(); | 2540 List<Label> labels = pop(); |
2538 SwitchCase current = cases[i] = pop(); | 2541 SwitchCase current = cases[i] = pop(); |
2539 for (Label label in labels) { | 2542 for (Label label in labels) { |
2540 JumpTarget target = switchScope.lookupLabel(label.name); | 2543 JumpTarget target = switchScope.lookupLabel(label.name); |
2541 if (target != null) { | 2544 if (target != null) { |
2542 target.resolveGotos(current); | 2545 target.resolveGotos(current); |
2543 } | 2546 } |
2544 } | 2547 } |
2545 // TODO(ahe): Validate that there's only one default and it's last. | 2548 } |
| 2549 // Check all but the last case for the following: |
| 2550 // 1. That it isn't a default case (which should be last). |
| 2551 // 2. That it doesn't fall through to the next case. |
| 2552 for (int i = 0; i < caseCount - 1; i++) { |
| 2553 SwitchCase current = cases[i]; |
| 2554 if (current.isDefault) { |
| 2555 addCompileTimeError(current.fileOffset, |
| 2556 "'default' switch case should be the last case."); |
| 2557 continue; |
| 2558 } |
| 2559 Block block = current.body; |
| 2560 // [block] is a synthetic block that is added to handle variable |
| 2561 // declarations in the switch case. |
| 2562 TreeNode lastNode = |
| 2563 block.statements.isEmpty ? null : block.statements.last; |
| 2564 if (lastNode is Block) { |
| 2565 // This is a non-synthetic block. |
| 2566 Block block = lastNode; |
| 2567 lastNode = block.statements.isEmpty ? null : block.statements.last; |
| 2568 } |
| 2569 if (lastNode is ExpressionStatement) { |
| 2570 ExpressionStatement statement = lastNode; |
| 2571 lastNode = statement.expression; |
| 2572 } |
| 2573 if (lastNode is! BreakStatement && |
| 2574 lastNode is! ContinueSwitchStatement && |
| 2575 lastNode is! Rethrow && |
| 2576 lastNode is! ReturnStatement && |
| 2577 lastNode is! Throw) { |
| 2578 block.addStatement( |
| 2579 new ExpressionStatement(buildFallThroughError(current.fileOffset))); |
| 2580 } |
2546 } | 2581 } |
2547 JumpTarget target = exitBreakTarget(); | 2582 JumpTarget target = exitBreakTarget(); |
2548 exitSwitchScope(); | 2583 exitSwitchScope(); |
2549 exitLocalScope(); | 2584 exitLocalScope(); |
2550 Expression expression = popForValue(); | 2585 Expression expression = popForValue(); |
2551 Statement result = new SwitchStatement(expression, cases); | 2586 Statement result = new SwitchStatement(expression, cases); |
2552 if (target.hasUsers) { | 2587 if (target.hasUsers) { |
2553 result = new LabeledStatement(result); | 2588 result = new LabeledStatement(result); |
2554 target.resolveBreaks(result); | 2589 target.resolveBreaks(result); |
2555 } | 2590 } |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2710 } | 2745 } |
2711 | 2746 |
2712 Expression wrapInCompileTimeError(Expression expression, String message) { | 2747 Expression wrapInCompileTimeError(Expression expression, String message) { |
2713 return new Let( | 2748 return new Let( |
2714 new VariableDeclaration.forValue(expression) | 2749 new VariableDeclaration.forValue(expression) |
2715 ..fileOffset = expression.fileOffset, | 2750 ..fileOffset = expression.fileOffset, |
2716 buildCompileTimeError(message, expression.fileOffset)) | 2751 buildCompileTimeError(message, expression.fileOffset)) |
2717 ..fileOffset = expression.fileOffset; | 2752 ..fileOffset = expression.fileOffset; |
2718 } | 2753 } |
2719 | 2754 |
| 2755 Expression buildFallThroughError(int charOffset) { |
| 2756 warningNotError("Switch case may fall through to next case.", charOffset); |
| 2757 Builder constructor = library.loader.getFallThroughError(); |
| 2758 return new Throw(buildStaticInvocation( |
| 2759 constructor.target, new Arguments.empty(), |
| 2760 charOffset: charOffset)); |
| 2761 } |
| 2762 |
2720 Expression buildAbstractClassInstantiationError(String className, | 2763 Expression buildAbstractClassInstantiationError(String className, |
2721 [int charOffset = -1]) { | 2764 [int charOffset = -1]) { |
2722 warning("The class '$className' is abstract and can't be instantiated.", | 2765 warning("The class '$className' is abstract and can't be instantiated.", |
2723 charOffset); | 2766 charOffset); |
2724 Builder constructor = library.loader.getAbstractClassInstantiationError(); | 2767 Builder constructor = library.loader.getAbstractClassInstantiationError(); |
2725 return new Throw(buildStaticInvocation(constructor.target, | 2768 return new Throw(buildStaticInvocation(constructor.target, |
2726 new KernelArguments(<Expression>[new StringLiteral(className)]))); | 2769 new KernelArguments(<Expression>[new StringLiteral(className)]))); |
2727 } | 2770 } |
2728 | 2771 |
2729 Statement buildCompileTimeErrorStatement(error, [int charOffset = -1]) { | 2772 Statement buildCompileTimeErrorStatement(error, [int charOffset = -1]) { |
(...skipping 644 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3374 if (starToken == null) { | 3417 if (starToken == null) { |
3375 return AsyncMarker.Async; | 3418 return AsyncMarker.Async; |
3376 } else { | 3419 } else { |
3377 assert(identical(starToken.stringValue, "*")); | 3420 assert(identical(starToken.stringValue, "*")); |
3378 return AsyncMarker.AsyncStar; | 3421 return AsyncMarker.AsyncStar; |
3379 } | 3422 } |
3380 } else { | 3423 } else { |
3381 return internalError("Unknown async modifier: $asyncToken"); | 3424 return internalError("Unknown async modifier: $asyncToken"); |
3382 } | 3425 } |
3383 } | 3426 } |
OLD | NEW |