| 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 |