| 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.analyzer.token_utils; | 5 library fasta.analyzer.token_utils; |
| 6 | 6 |
| 7 import 'package:front_end/src/fasta/parser/error_kind.dart' show | 7 import 'package:front_end/src/fasta/parser/error_kind.dart' show |
| 8 ErrorKind; | 8 ErrorKind; |
| 9 | 9 |
| 10 import 'package:front_end/src/fasta/scanner/error_token.dart' show | 10 import 'package:front_end/src/fasta/scanner/error_token.dart' show |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 56 List<Object> arguments)) { | 56 List<Object> arguments)) { |
| 57 var analyzerTokenHead = new analyzer.Token(null, 0); | 57 var analyzerTokenHead = new analyzer.Token(null, 0); |
| 58 analyzerTokenHead.previous = analyzerTokenHead; | 58 analyzerTokenHead.previous = analyzerTokenHead; |
| 59 var analyzerTokenTail = analyzerTokenHead; | 59 var analyzerTokenTail = analyzerTokenHead; |
| 60 // TODO(paulberry,ahe): Fasta includes comments directly in the token | 60 // TODO(paulberry,ahe): Fasta includes comments directly in the token |
| 61 // stream, rather than pointing to them via a "precedingComment" pointer, as | 61 // stream, rather than pointing to them via a "precedingComment" pointer, as |
| 62 // analyzer does. This seems like it will complicate parsing and other | 62 // analyzer does. This seems like it will complicate parsing and other |
| 63 // operations. | 63 // operations. |
| 64 analyzer.CommentToken currentCommentHead; | 64 analyzer.CommentToken currentCommentHead; |
| 65 analyzer.CommentToken currentCommentTail; | 65 analyzer.CommentToken currentCommentTail; |
| 66 |
| 67 // Both fasta and analyzer have links from a "BeginToken" to its matching |
| 68 // "EndToken" in a group (like parentheses and braces). However, fasta may |
| 69 // contain synthetic tokens from error recovery that are not mapped to the |
| 70 // analyzer token stream. We use these stacks to create the appropriate links |
| 71 // for non-synthetic tokens in the way analyzer expects. |
| 72 |
| 66 // Note: beginTokenStack and endTokenStack are seeded with a sentinel value | 73 // Note: beginTokenStack and endTokenStack are seeded with a sentinel value |
| 67 // so that we don't have to check if they're empty. | 74 // so that we don't have to check if they're empty. |
| 68 var beginTokenStack = <analyzer.BeginToken>[null]; | 75 var beginTokenStack = <analyzer.BeginToken>[null]; |
| 69 var endTokenStack = <Token>[null]; | 76 var endTokenStack = <Token>[null]; |
| 77 |
| 70 void matchGroups(Token token, analyzer.Token translatedToken) { | 78 void matchGroups(Token token, analyzer.Token translatedToken) { |
| 71 // If this token closes a group, set the corresponding opener token | |
| 72 // to point to it. | |
| 73 if (identical(endTokenStack.last, token)) { | 79 if (identical(endTokenStack.last, token)) { |
| 74 beginTokenStack.last.endToken = translatedToken; | 80 beginTokenStack.last.endToken = translatedToken; |
| 75 beginTokenStack.removeLast(); | 81 beginTokenStack.removeLast(); |
| 76 endTokenStack.removeLast(); | 82 endTokenStack.removeLast(); |
| 77 } | 83 } |
| 78 // If this token opens a group, and there is a matching closer that's not | 84 // Synthetic end tokens use the same offset as the begin token. |
| 79 // synthetic, put it on the stack. The easiest way to tell whether the | |
| 80 // closer is synthetic is to see if it has the same offset as the opener. | |
| 81 if (translatedToken is analyzer.BeginToken && | 85 if (translatedToken is analyzer.BeginToken && |
| 82 token is BeginGroupToken && | 86 token is BeginGroupToken && |
| 83 token.endGroup != null && | 87 token.endGroup != null && |
| 84 token.endGroup.charOffset != token.charOffset) { | 88 token.endGroup.charOffset != token.charOffset) { |
| 85 beginTokenStack.add(translatedToken); | 89 beginTokenStack.add(translatedToken); |
| 86 endTokenStack.add(token.endGroup); | 90 endTokenStack.add(token.endGroup); |
| 87 } | 91 } |
| 88 } | 92 } |
| 89 | 93 |
| 90 while (true) { | 94 while (true) { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 123 | 127 |
| 124 /// Converts a stream of Analyzer tokens (starting with [token] and continuing | 128 /// Converts a stream of Analyzer tokens (starting with [token] and continuing |
| 125 /// to EOF) to a stream of Fasta tokens. | 129 /// to EOF) to a stream of Fasta tokens. |
| 126 /// | 130 /// |
| 127 /// TODO(paulberry): Analyzer tokens do not record error conditions, so a round | 131 /// TODO(paulberry): Analyzer tokens do not record error conditions, so a round |
| 128 /// trip through this function and [toAnalyzerTokenStream] will lose error | 132 /// trip through this function and [toAnalyzerTokenStream] will lose error |
| 129 /// information. | 133 /// information. |
| 130 Token fromAnalyzerTokenStream(analyzer.Token analyzerToken) { | 134 Token fromAnalyzerTokenStream(analyzer.Token analyzerToken) { |
| 131 Token tokenHead = new SymbolToken(EOF_INFO, -1); | 135 Token tokenHead = new SymbolToken(EOF_INFO, -1); |
| 132 Token tokenTail = tokenHead; | 136 Token tokenTail = tokenHead; |
| 137 |
| 138 // Both fasta and analyzer have links from a "BeginToken" to its matching |
| 139 // "EndToken" in a group (like parentheses and braces). However, only fasta |
| 140 // makes these links for angle brackets. We use these stacks to map the |
| 141 // links from the analyzer token stream into equivalent links in the fasta |
| 142 // token stream, and to create the links that fasta expects for angle |
| 143 // brackets. |
| 144 |
| 133 // Note: beginTokenStack and endTokenStack are seeded with a sentinel value | 145 // Note: beginTokenStack and endTokenStack are seeded with a sentinel value |
| 134 // so that we don't have to check if they're empty. | 146 // so that we don't have to check if they're empty. |
| 135 var beginTokenStack = <BeginGroupToken>[null]; | 147 var beginTokenStack = <BeginGroupToken>[null]; |
| 136 var endTokenStack = <analyzer.Token>[null]; | 148 var endTokenStack = <analyzer.Token>[null]; |
| 137 var angleBracketStack = <BeginGroupToken>[]; | 149 var angleBracketStack = <BeginGroupToken>[]; |
| 138 void matchGroups(analyzer.Token analyzerToken, Token translatedToken) { | 150 void matchGroups(analyzer.Token analyzerToken, Token translatedToken) { |
| 139 // If this token closes a group, set the corresponding opener token to point | |
| 140 // to it. | |
| 141 if (identical(endTokenStack.last, analyzerToken)) { | 151 if (identical(endTokenStack.last, analyzerToken)) { |
| 142 angleBracketStack.clear(); | 152 angleBracketStack.clear(); |
| 143 beginTokenStack.last.endGroup = translatedToken; | 153 beginTokenStack.last.endGroup = translatedToken; |
| 144 beginTokenStack.removeLast(); | 154 beginTokenStack.removeLast(); |
| 145 endTokenStack.removeLast(); | 155 endTokenStack.removeLast(); |
| 146 } else if (translatedToken.info.kind == LT_TOKEN) { | 156 } else if (translatedToken.info.kind == LT_TOKEN) { |
| 147 BeginGroupToken beginGroupToken = translatedToken; | 157 BeginGroupToken beginGroupToken = translatedToken; |
| 148 angleBracketStack.add(beginGroupToken); | 158 angleBracketStack.add(beginGroupToken); |
| 149 } else if (translatedToken.info.kind == GT_TOKEN && | 159 } else if (translatedToken.info.kind == GT_TOKEN && |
| 150 angleBracketStack.isNotEmpty) { | 160 angleBracketStack.isNotEmpty) { |
| 151 angleBracketStack.removeLast().endGroup = translatedToken; | 161 angleBracketStack.removeLast().endGroup = translatedToken; |
| 152 } else if (translatedToken.info.kind == GT_GT_TOKEN && | 162 } else if (translatedToken.info.kind == GT_GT_TOKEN && |
| 153 angleBracketStack.isNotEmpty) { | 163 angleBracketStack.isNotEmpty) { |
| 154 angleBracketStack.removeLast(); | 164 angleBracketStack.removeLast(); |
| 155 if (angleBracketStack.isNotEmpty) { | 165 if (angleBracketStack.isNotEmpty) { |
| 156 angleBracketStack.removeLast().endGroup = translatedToken; | 166 angleBracketStack.removeLast().endGroup = translatedToken; |
| 157 } | 167 } |
| 158 } | 168 } |
| 159 // If this token opens a group, and there is a matching closer, put it on | |
| 160 // the stack. | |
| 161 // TODO(paulberry): generate synthetic closer tokens and "UnmatchedToken" | 169 // TODO(paulberry): generate synthetic closer tokens and "UnmatchedToken" |
| 162 // tokens as appropriate. | 170 // tokens as appropriate. |
| 163 if (translatedToken is BeginGroupToken && | 171 if (translatedToken is BeginGroupToken && |
| 164 analyzerToken is analyzer.BeginToken && | 172 analyzerToken is analyzer.BeginToken && |
| 165 analyzerToken.endToken != null) { | 173 analyzerToken.endToken != null) { |
| 166 angleBracketStack.clear(); | 174 angleBracketStack.clear(); |
| 167 beginTokenStack.add(translatedToken); | 175 beginTokenStack.add(translatedToken); |
| 168 endTokenStack.add(analyzerToken.endToken); | 176 endTokenStack.add(analyzerToken.endToken); |
| 169 } | 177 } |
| 170 } | 178 } |
| (...skipping 477 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 648 case BACKSLASH_TOKEN: return TokenType.BACKSLASH; | 656 case BACKSLASH_TOKEN: return TokenType.BACKSLASH; |
| 649 case PERIOD_PERIOD_PERIOD_TOKEN: return TokenType.PERIOD_PERIOD_PERIOD; | 657 case PERIOD_PERIOD_PERIOD_TOKEN: return TokenType.PERIOD_PERIOD_PERIOD; |
| 650 // case GENERIC_METHOD_TYPE_LIST_TOKEN: | 658 // case GENERIC_METHOD_TYPE_LIST_TOKEN: |
| 651 // return TokenType.GENERIC_METHOD_TYPE_LIST; | 659 // return TokenType.GENERIC_METHOD_TYPE_LIST; |
| 652 // case GENERIC_METHOD_TYPE_ASSIGN_TOKEN: | 660 // case GENERIC_METHOD_TYPE_ASSIGN_TOKEN: |
| 653 // return TokenType.GENERIC_METHOD_TYPE_ASSIGN; | 661 // return TokenType.GENERIC_METHOD_TYPE_ASSIGN; |
| 654 default: | 662 default: |
| 655 return internalError("Unhandled token ${token.info}"); | 663 return internalError("Unhandled token ${token.info}"); |
| 656 } | 664 } |
| 657 } | 665 } |
| OLD | NEW |