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.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 |
| 11 ErrorToken; | 11 ErrorToken, |
| 12 UnmatchedToken; | |
| 12 | 13 |
| 13 import 'package:front_end/src/fasta/scanner/keyword.dart' show | 14 import 'package:front_end/src/fasta/scanner/keyword.dart' show |
| 14 Keyword; | 15 Keyword; |
| 15 | 16 |
| 16 import 'package:front_end/src/fasta/scanner/precedence.dart'; | 17 import 'package:front_end/src/fasta/scanner/precedence.dart'; |
| 17 | 18 |
| 18 import 'package:front_end/src/fasta/scanner/token.dart' show | 19 import 'package:front_end/src/fasta/scanner/token.dart' show |
| 19 BeginGroupToken, | 20 BeginGroupToken, |
| 20 KeywordToken, | 21 KeywordToken, |
| 21 StringToken, | 22 StringToken, |
| 22 SymbolToken, | 23 SymbolToken, |
| 23 Token; | 24 Token; |
| 24 | 25 |
| 25 import 'package:front_end/src/fasta/scanner/token_constants.dart'; | 26 import 'package:front_end/src/fasta/scanner/token_constants.dart'; |
| 26 | 27 |
| 27 import 'package:front_end/src/scanner/token.dart' as analyzer show | 28 import 'package:front_end/src/scanner/token.dart' as analyzer show |
| 29 BeginToken, | |
| 30 BeginTokenWithComment, | |
| 28 CommentToken, | 31 CommentToken, |
| 29 Keyword, | 32 Keyword, |
| 30 KeywordToken, | 33 KeywordToken, |
| 31 KeywordTokenWithComment, | 34 KeywordTokenWithComment, |
| 32 StringToken, | 35 StringToken, |
| 33 StringTokenWithComment, | 36 StringTokenWithComment, |
| 34 Token, | 37 Token, |
| 35 TokenWithComment; | 38 TokenWithComment; |
| 36 | 39 |
| 37 import 'package:front_end/src/scanner/errors.dart' as analyzer show | 40 import 'package:front_end/src/scanner/errors.dart' as analyzer show |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 54 List<Object> arguments)) { | 57 List<Object> arguments)) { |
| 55 var analyzerTokenHead = new analyzer.Token(null, 0); | 58 var analyzerTokenHead = new analyzer.Token(null, 0); |
| 56 analyzerTokenHead.previous = analyzerTokenHead; | 59 analyzerTokenHead.previous = analyzerTokenHead; |
| 57 var analyzerTokenTail = analyzerTokenHead; | 60 var analyzerTokenTail = analyzerTokenHead; |
| 58 // TODO(paulberry,ahe): Fasta includes comments directly in the token | 61 // TODO(paulberry,ahe): Fasta includes comments directly in the token |
| 59 // stream, rather than pointing to them via a "precedingComment" pointer, as | 62 // stream, rather than pointing to them via a "precedingComment" pointer, as |
| 60 // analyzer does. This seems like it will complicate parsing and other | 63 // analyzer does. This seems like it will complicate parsing and other |
| 61 // operations. | 64 // operations. |
| 62 analyzer.CommentToken currentCommentHead; | 65 analyzer.CommentToken currentCommentHead; |
| 63 analyzer.CommentToken currentCommentTail; | 66 analyzer.CommentToken currentCommentTail; |
| 67 // Note: beginTokenStack and endTokenStack are seeded with a sentinel value | |
| 68 // so that we don't have to check if they're empty. | |
| 69 var beginTokenStack = <analyzer.BeginToken>[null]; | |
| 70 var endTokenStack = <Token>[null]; | |
| 71 void matchGroups(Token token, analyzer.Token translatedToken) { | |
| 72 // If this token closes a group, set the corresponding opener token | |
|
Siggi Cherem (dart-lang)
2017/02/15 00:23:10
super optional nit - (IMO not worth making a chang
| |
| 73 // to point to it. | |
| 74 if (identical(endTokenStack.last, token)) { | |
| 75 beginTokenStack.last.endToken = translatedToken; | |
| 76 beginTokenStack.removeLast(); | |
| 77 endTokenStack.removeLast(); | |
| 78 } | |
| 79 // If this token opens a group, and there is a matching closer that's not | |
|
Siggi Cherem (dart-lang)
2017/02/15 00:23:10
minor terminology nit here: consider using closing
| |
| 80 // synthetic, put it on the stack. The easiest way to tell whether the | |
| 81 // closer is synthetic is to see if it has the same offset as the opener. | |
| 82 if (translatedToken is analyzer.BeginToken && token is BeginGroupToken && | |
| 83 token.endGroup != null && token.endGroup.charOffset != token.charOffset) { | |
|
ahe
2017/02/14 11:28:32
Long line.
Paul Berry
2017/02/14 12:40:39
Sorry. My usual workflow is hampered by not being
| |
| 84 beginTokenStack.add(translatedToken); | |
| 85 endTokenStack.add(token.endGroup); | |
| 86 } | |
| 87 } | |
| 88 | |
| 64 while (true) { | 89 while (true) { |
| 65 if (token.info.kind == BAD_INPUT_TOKEN) { | 90 if (token.info.kind == BAD_INPUT_TOKEN) { |
| 66 ErrorToken errorToken = token; | 91 ErrorToken errorToken = token; |
| 67 _translateErrorToken(errorToken, reportError); | 92 _translateErrorToken(errorToken, reportError); |
| 68 } else if (token.info.kind == COMMENT_TOKEN) { | 93 } else if (token.info.kind == COMMENT_TOKEN) { |
| 69 // TODO(paulberry,ahe): It would be nice if the scanner gave us an | 94 // TODO(paulberry,ahe): It would be nice if the scanner gave us an |
| 70 // easier way to distinguish between the two types of comment. | 95 // easier way to distinguish between the two types of comment. |
| 71 var type = token.value.startsWith('/*') | 96 var type = token.value.startsWith('/*') |
| 72 ? TokenType.MULTI_LINE_COMMENT | 97 ? TokenType.MULTI_LINE_COMMENT |
| 73 : TokenType.SINGLE_LINE_COMMENT; | 98 : TokenType.SINGLE_LINE_COMMENT; |
| 74 var translatedToken = | 99 var translatedToken = |
| 75 new analyzer.CommentToken(type, token.value, token.charOffset); | 100 new analyzer.CommentToken(type, token.value, token.charOffset); |
| 76 if (currentCommentHead == null) { | 101 if (currentCommentHead == null) { |
| 77 currentCommentHead = currentCommentTail = translatedToken; | 102 currentCommentHead = currentCommentTail = translatedToken; |
| 78 } else { | 103 } else { |
| 79 currentCommentTail.setNext(translatedToken); | 104 currentCommentTail.setNext(translatedToken); |
| 80 currentCommentTail = translatedToken; | 105 currentCommentTail = translatedToken; |
| 81 } | 106 } |
| 82 } else { | 107 } else { |
| 83 var translatedToken = toAnalyzerToken(token, currentCommentHead); | 108 var translatedToken = toAnalyzerToken(token, currentCommentHead); |
| 109 matchGroups(token, translatedToken); | |
| 84 translatedToken.setNext(translatedToken); | 110 translatedToken.setNext(translatedToken); |
| 85 currentCommentHead = currentCommentTail = null; | 111 currentCommentHead = currentCommentTail = null; |
| 86 analyzerTokenTail.setNext(translatedToken); | 112 analyzerTokenTail.setNext(translatedToken); |
| 87 translatedToken.previous = analyzerTokenTail; | 113 translatedToken.previous = analyzerTokenTail; |
| 88 analyzerTokenTail = translatedToken; | 114 analyzerTokenTail = translatedToken; |
| 89 } | 115 } |
| 90 if (token.isEof) { | 116 if (token.isEof) { |
| 91 return analyzerTokenHead.next; | 117 return analyzerTokenHead.next; |
| 92 } | 118 } |
| 93 token = token.next; | 119 token = token.next; |
| 94 } | 120 } |
| 95 } | 121 } |
| 96 | 122 |
| 97 /// Converts a stream of Analyzer tokens (starting with [token] and continuing | 123 /// Converts a stream of Analyzer tokens (starting with [token] and continuing |
| 98 /// to EOF) to a stream of Fasta tokens. | 124 /// to EOF) to a stream of Fasta tokens. |
| 99 /// | 125 /// |
| 100 /// TODO(paulberry): Analyzer tokens do not record error conditions, so a round | 126 /// TODO(paulberry): Analyzer tokens do not record error conditions, so a round |
| 101 /// trip through this function and [toAnalyzerTokenStream] will lose error | 127 /// trip through this function and [toAnalyzerTokenStream] will lose error |
| 102 /// information. | 128 /// information. |
| 103 Token fromAnalyzerTokenStream(analyzer.Token analyzerToken) { | 129 Token fromAnalyzerTokenStream(analyzer.Token analyzerToken) { |
| 104 Token tokenHead = new SymbolToken(EOF_INFO, -1); | 130 Token tokenHead = new SymbolToken(EOF_INFO, -1); |
| 105 Token tokenTail = tokenHead; | 131 Token tokenTail = tokenHead; |
| 132 // Note: beginTokenStack and endTokenStack are seeded with a sentinel value | |
| 133 // so that we don't have to check if they're empty. | |
| 134 var beginTokenStack = <BeginGroupToken>[null]; | |
| 135 var endTokenStack = <analyzer.Token>[null]; | |
| 136 void matchGroups(analyzer.Token analyzerToken, Token translatedToken) { | |
| 137 // If this token closes a group, set the corresponding opener token to point | |
| 138 // to it. | |
| 139 if (identical(endTokenStack.last, analyzerToken)) { | |
| 140 beginTokenStack.last.endGroup = translatedToken; | |
| 141 beginTokenStack.removeLast(); | |
| 142 endTokenStack.removeLast(); | |
| 143 } | |
| 144 // If this token opens a group, and there is a matching closer, put it on | |
| 145 // the stack. | |
| 146 // TODO(paulberry): generate synthetic closer tokens and "UnmatchedToken" | |
| 147 // tokens as appropriate. | |
| 148 // TODO(paulberry): match up "<" and ">"/">>" (analyzer doesn't match | |
| 149 // these). | |
| 150 if (translatedToken is BeginGroupToken && analyzerToken is analyzer.BeginTok en && | |
|
ahe
2017/02/14 11:28:32
Long line.
Paul Berry
2017/02/14 12:40:39
Done.
| |
| 151 analyzerToken.endToken != null) { | |
| 152 beginTokenStack.add(translatedToken); | |
| 153 endTokenStack.add(analyzerToken.endToken); | |
| 154 } | |
| 155 } | |
| 106 analyzer.Token translateAndAppend(analyzer.Token analyzerToken) { | 156 analyzer.Token translateAndAppend(analyzer.Token analyzerToken) { |
| 107 var token = fromAnalyzerToken(analyzerToken); | 157 var token = fromAnalyzerToken(analyzerToken); |
| 108 tokenTail.next = token; | 158 tokenTail.next = token; |
| 109 tokenTail = token; | 159 tokenTail = token; |
| 160 matchGroups(analyzerToken, token); | |
| 110 return analyzerToken.next; | 161 return analyzerToken.next; |
| 111 } | 162 } |
| 112 | 163 |
| 113 while (true) { | 164 while (true) { |
| 114 analyzer.Token commentToken = analyzerToken.precedingComments; | 165 analyzer.Token commentToken = analyzerToken.precedingComments; |
| 115 while (commentToken != null) { | 166 while (commentToken != null) { |
| 116 commentToken = translateAndAppend(commentToken); | 167 commentToken = translateAndAppend(commentToken); |
| 117 } | 168 } |
| 118 // TODO(paulberry): join up begingroup/endgroup. | 169 // TODO(paulberry): join up begingroup/endgroup. |
| 119 if (analyzerToken.type == TokenType.EOF) { | 170 if (analyzerToken.type == TokenType.EOF) { |
| (...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 373 if (token == null) return null; | 424 if (token == null) return null; |
| 374 analyzer.Token makeStringToken(TokenType tokenType) { | 425 analyzer.Token makeStringToken(TokenType tokenType) { |
| 375 if (commentToken == null) { | 426 if (commentToken == null) { |
| 376 return new analyzer.StringToken(tokenType, token.value, token.charOffset); | 427 return new analyzer.StringToken(tokenType, token.value, token.charOffset); |
| 377 } else { | 428 } else { |
| 378 return new analyzer.StringTokenWithComment( | 429 return new analyzer.StringTokenWithComment( |
| 379 tokenType, token.value, token.charOffset, commentToken); | 430 tokenType, token.value, token.charOffset, commentToken); |
| 380 } | 431 } |
| 381 } | 432 } |
| 382 | 433 |
| 434 analyzer.Token makeBeginToken(TokenType tokenType) { | |
| 435 if (commentToken == null) { | |
| 436 return new analyzer.BeginToken(tokenType, token.charOffset); | |
| 437 } else { | |
| 438 return new analyzer.BeginTokenWithComment(tokenType, token.charOffset, com mentToken); | |
|
ahe
2017/02/14 11:28:32
Long line.
Paul Berry
2017/02/14 12:40:39
Done.
| |
| 439 } | |
| 440 } | |
| 441 | |
| 383 switch (token.kind) { | 442 switch (token.kind) { |
| 384 case DOUBLE_TOKEN: | 443 case DOUBLE_TOKEN: |
| 385 return makeStringToken(TokenType.DOUBLE); | 444 return makeStringToken(TokenType.DOUBLE); |
| 386 | 445 |
| 387 case HEXADECIMAL_TOKEN: | 446 case HEXADECIMAL_TOKEN: |
| 388 return makeStringToken(TokenType.HEXADECIMAL); | 447 return makeStringToken(TokenType.HEXADECIMAL); |
| 389 | 448 |
| 390 case IDENTIFIER_TOKEN: | 449 case IDENTIFIER_TOKEN: |
| 391 return makeStringToken(TokenType.IDENTIFIER); | 450 return makeStringToken(TokenType.IDENTIFIER); |
| 392 | 451 |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 416 return new analyzer.KeywordToken(keyword, token.charOffset); | 475 return new analyzer.KeywordToken(keyword, token.charOffset); |
| 417 } else { | 476 } else { |
| 418 return new analyzer.KeywordTokenWithComment( | 477 return new analyzer.KeywordTokenWithComment( |
| 419 keyword, token.charOffset, commentToken); | 478 keyword, token.charOffset, commentToken); |
| 420 } | 479 } |
| 421 break; | 480 break; |
| 422 | 481 |
| 423 case STRING_TOKEN: | 482 case STRING_TOKEN: |
| 424 return makeStringToken(TokenType.STRING); | 483 return makeStringToken(TokenType.STRING); |
| 425 | 484 |
| 485 case OPEN_CURLY_BRACKET_TOKEN: | |
| 486 case OPEN_SQUARE_BRACKET_TOKEN: | |
| 487 case OPEN_PAREN_TOKEN: | |
| 488 case STRING_INTERPOLATION_TOKEN: | |
| 489 return makeBeginToken(getTokenType(token)); | |
| 490 | |
| 426 default: | 491 default: |
| 427 if (commentToken == null) { | 492 if (commentToken == null) { |
| 428 return new analyzer.Token(getTokenType(token), token.charOffset); | 493 return new analyzer.Token(getTokenType(token), token.charOffset); |
| 429 } else { | 494 } else { |
| 430 return new analyzer.TokenWithComment( | 495 return new analyzer.TokenWithComment( |
| 431 getTokenType(token), token.charOffset, commentToken); | 496 getTokenType(token), token.charOffset, commentToken); |
| 432 } | 497 } |
| 433 break; | 498 break; |
| 434 } | 499 } |
| 435 } | 500 } |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 566 case BACKSLASH_TOKEN: return TokenType.BACKSLASH; | 631 case BACKSLASH_TOKEN: return TokenType.BACKSLASH; |
| 567 case PERIOD_PERIOD_PERIOD_TOKEN: return TokenType.PERIOD_PERIOD_PERIOD; | 632 case PERIOD_PERIOD_PERIOD_TOKEN: return TokenType.PERIOD_PERIOD_PERIOD; |
| 568 // case GENERIC_METHOD_TYPE_LIST_TOKEN: | 633 // case GENERIC_METHOD_TYPE_LIST_TOKEN: |
| 569 // return TokenType.GENERIC_METHOD_TYPE_LIST; | 634 // return TokenType.GENERIC_METHOD_TYPE_LIST; |
| 570 // case GENERIC_METHOD_TYPE_ASSIGN_TOKEN: | 635 // case GENERIC_METHOD_TYPE_ASSIGN_TOKEN: |
| 571 // return TokenType.GENERIC_METHOD_TYPE_ASSIGN; | 636 // return TokenType.GENERIC_METHOD_TYPE_ASSIGN; |
| 572 default: | 637 default: |
| 573 return internalError("Unhandled token ${token.info}"); | 638 return internalError("Unhandled token ${token.info}"); |
| 574 } | 639 } |
| 575 } | 640 } |
| OLD | NEW |