| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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.parser.parser; | 5 library fasta.parser.parser; |
| 6 | 6 |
| 7 import '../fasta_codes.dart' | 7 import '../fasta_codes.dart' |
| 8 show | 8 show |
| 9 FastaCode, | 9 FastaCode, |
| 10 FastaMessage, | 10 FastaMessage, |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 58 | 58 |
| 59 import '../scanner/recover.dart' show closeBraceFor, skipToEof; | 59 import '../scanner/recover.dart' show closeBraceFor, skipToEof; |
| 60 | 60 |
| 61 import '../scanner/keyword.dart' show Keyword; | 61 import '../scanner/keyword.dart' show Keyword; |
| 62 | 62 |
| 63 import '../scanner/precedence.dart' | 63 import '../scanner/precedence.dart' |
| 64 show | 64 show |
| 65 ASSIGNMENT_PRECEDENCE, | 65 ASSIGNMENT_PRECEDENCE, |
| 66 AS_INFO, | 66 AS_INFO, |
| 67 CASCADE_PRECEDENCE, | 67 CASCADE_PRECEDENCE, |
| 68 EOF_INFO, | |
| 69 EQUALITY_PRECEDENCE, | 68 EQUALITY_PRECEDENCE, |
| 70 GENERIC_METHOD_TYPE_ASSIGN, | |
| 71 GENERIC_METHOD_TYPE_LIST, | |
| 72 GT_INFO, | 69 GT_INFO, |
| 73 IS_INFO, | 70 IS_INFO, |
| 74 MINUS_MINUS_INFO, | 71 MINUS_MINUS_INFO, |
| 75 OPEN_PAREN_INFO, | 72 OPEN_PAREN_INFO, |
| 76 OPEN_SQUARE_BRACKET_INFO, | 73 OPEN_SQUARE_BRACKET_INFO, |
| 77 PERIOD_INFO, | 74 PERIOD_INFO, |
| 78 PLUS_PLUS_INFO, | 75 PLUS_PLUS_INFO, |
| 79 POSTFIX_PRECEDENCE, | 76 POSTFIX_PRECEDENCE, |
| 80 PrecedenceInfo, | 77 PrecedenceInfo, |
| 81 QUESTION_INFO, | 78 QUESTION_INFO, |
| 82 QUESTION_PERIOD_INFO, | 79 QUESTION_PERIOD_INFO, |
| 83 RELATIONAL_PRECEDENCE, | 80 RELATIONAL_PRECEDENCE, |
| 84 SCRIPT_INFO; | 81 SCRIPT_INFO; |
| 85 | 82 |
| 86 import '../scanner/token.dart' | 83 import '../scanner/token.dart' |
| 87 show | 84 show |
| 88 BeginGroupToken, | 85 BeginGroupToken, |
| 89 CommentToken, | |
| 90 KeywordToken, | 86 KeywordToken, |
| 91 SymbolToken, | 87 SymbolToken, |
| 92 Token, | 88 Token, |
| 93 isUserDefinableOperator; | 89 isUserDefinableOperator; |
| 94 | 90 |
| 95 import '../scanner/token_constants.dart' | 91 import '../scanner/token_constants.dart' |
| 96 show | 92 show |
| 97 COMMA_TOKEN, | 93 COMMA_TOKEN, |
| 98 DOUBLE_TOKEN, | 94 DOUBLE_TOKEN, |
| 99 EOF_TOKEN, | 95 EOF_TOKEN, |
| (...skipping 10 matching lines...) Expand all Loading... |
| 110 OPEN_CURLY_BRACKET_TOKEN, | 106 OPEN_CURLY_BRACKET_TOKEN, |
| 111 OPEN_PAREN_TOKEN, | 107 OPEN_PAREN_TOKEN, |
| 112 OPEN_SQUARE_BRACKET_TOKEN, | 108 OPEN_SQUARE_BRACKET_TOKEN, |
| 113 PERIOD_TOKEN, | 109 PERIOD_TOKEN, |
| 114 SEMICOLON_TOKEN, | 110 SEMICOLON_TOKEN, |
| 115 STRING_INTERPOLATION_IDENTIFIER_TOKEN, | 111 STRING_INTERPOLATION_IDENTIFIER_TOKEN, |
| 116 STRING_INTERPOLATION_TOKEN, | 112 STRING_INTERPOLATION_TOKEN, |
| 117 STRING_TOKEN; | 113 STRING_TOKEN; |
| 118 | 114 |
| 119 import '../scanner/characters.dart' show $CLOSE_CURLY_BRACKET; | 115 import '../scanner/characters.dart' show $CLOSE_CURLY_BRACKET; |
| 120 import '../scanner/string_scanner.dart'; | |
| 121 | 116 |
| 122 import '../util/link.dart' show Link; | 117 import '../util/link.dart' show Link; |
| 123 | 118 |
| 124 import 'async_modifier.dart' show AsyncModifier; | 119 import 'async_modifier.dart' show AsyncModifier; |
| 125 | 120 |
| 126 import 'listener.dart' show Listener; | 121 import 'listener.dart' show Listener; |
| 127 | 122 |
| 128 import 'identifier_context.dart' show IdentifierContext; | 123 import 'identifier_context.dart' show IdentifierContext; |
| 129 | 124 |
| 130 /// Returns true if [token] is the symbol or keyword [value]. | 125 /// Returns true if [token] is the symbol or keyword [value]. |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 182 /// | 177 /// |
| 183 /// Historically, we over-used identical, and when identical is used on other | 178 /// Historically, we over-used identical, and when identical is used on other |
| 184 /// objects than strings, it can often be replaced by `==`. | 179 /// objects than strings, it can often be replaced by `==`. |
| 185 class Parser { | 180 class Parser { |
| 186 final Listener listener; | 181 final Listener listener; |
| 187 | 182 |
| 188 Uri get uri => listener.uri; | 183 Uri get uri => listener.uri; |
| 189 | 184 |
| 190 bool mayParseFunctionExpressions = true; | 185 bool mayParseFunctionExpressions = true; |
| 191 | 186 |
| 192 bool parseGenericMethodComments = false; | |
| 193 | |
| 194 /// Represents parser state: what asynchronous syntax is allowed in the | 187 /// Represents parser state: what asynchronous syntax is allowed in the |
| 195 /// function being currently parsed. In rare situations, this can be set by | 188 /// function being currently parsed. In rare situations, this can be set by |
| 196 /// external clients, for example, to parse an expression outside a function. | 189 /// external clients, for example, to parse an expression outside a function. |
| 197 AsyncModifier asyncState = AsyncModifier.Sync; | 190 AsyncModifier asyncState = AsyncModifier.Sync; |
| 198 | 191 |
| 199 Parser(this.listener); | 192 Parser(this.listener); |
| 200 | 193 |
| 201 bool get inGenerator { | 194 bool get inGenerator { |
| 202 return asyncState == AsyncModifier.AsyncStar || | 195 return asyncState == AsyncModifier.AsyncStar || |
| 203 asyncState == AsyncModifier.SyncStar; | 196 asyncState == AsyncModifier.SyncStar; |
| (...skipping 429 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 633 token = expect('.', token.next); | 626 token = expect('.', token.next); |
| 634 nameToken = token; | 627 nameToken = token; |
| 635 token = parseIdentifier(token, IdentifierContext.fieldInitializer); | 628 token = parseIdentifier(token, IdentifierContext.fieldInitializer); |
| 636 } else { | 629 } else { |
| 637 nameToken = token; | 630 nameToken = token; |
| 638 token = parseIdentifier( | 631 token = parseIdentifier( |
| 639 token, IdentifierContext.formalParameterDeclaration); | 632 token, IdentifierContext.formalParameterDeclaration); |
| 640 } | 633 } |
| 641 } | 634 } |
| 642 | 635 |
| 643 token = _injectGenericCommentTypeList(token); | 636 token = listener.injectGenericCommentTypeList(token); |
| 644 if (optional('(', token)) { | 637 if (optional('(', token)) { |
| 645 Token inlineFunctionTypeStart = token; | 638 Token inlineFunctionTypeStart = token; |
| 646 listener.beginFunctionTypedFormalParameter(token); | 639 listener.beginFunctionTypedFormalParameter(token); |
| 647 listener.handleNoTypeVariables(token); | 640 listener.handleNoTypeVariables(token); |
| 648 token = parseFormalParameters(token); | 641 token = parseFormalParameters(token); |
| 649 listener.endFunctionTypedFormalParameter( | 642 listener.endFunctionTypedFormalParameter( |
| 650 covariantKeyword, thisKeyword, kind); | 643 covariantKeyword, thisKeyword, kind); |
| 651 // Generalized function types don't allow inline function types. | 644 // Generalized function types don't allow inline function types. |
| 652 // The following isn't allowed: | 645 // The following isn't allowed: |
| 653 // int Function(int bar(String x)). | 646 // int Function(int bar(String x)). |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 719 } else { | 712 } else { |
| 720 return expect(']', token); | 713 return expect(']', token); |
| 721 } | 714 } |
| 722 } | 715 } |
| 723 | 716 |
| 724 Token parseTypeOpt(Token token) { | 717 Token parseTypeOpt(Token token) { |
| 725 if (isGeneralizedFunctionType(token)) { | 718 if (isGeneralizedFunctionType(token)) { |
| 726 // Function type without return type. | 719 // Function type without return type. |
| 727 return parseType(token); | 720 return parseType(token); |
| 728 } | 721 } |
| 722 token = listener.injectGenericCommentTypeAssign(token); |
| 729 Token peek = peekAfterIfType(token); | 723 Token peek = peekAfterIfType(token); |
| 730 if (peek != null && (peek.isIdentifier() || optional('this', peek))) { | 724 if (peek != null && (peek.isIdentifier() || optional('this', peek))) { |
| 731 return parseType(token); | 725 return parseType(token); |
| 732 } | 726 } |
| 733 listener.handleNoType(token); | 727 listener.handleNoType(token); |
| 734 return token; | 728 return token; |
| 735 } | 729 } |
| 736 | 730 |
| 737 bool isValidTypeReference(Token token) { | 731 bool isValidTypeReference(Token token) { |
| 738 final kind = token.kind; | 732 final kind = token.kind; |
| (...skipping 372 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1111 token, | 1105 token, |
| 1112 (t) => listener.beginTypeVariables(t), | 1106 (t) => listener.beginTypeVariables(t), |
| 1113 (t) => parseTypeVariable(t), | 1107 (t) => parseTypeVariable(t), |
| 1114 (c, bt, et) => listener.endTypeVariables(c, bt, et), | 1108 (c, bt, et) => listener.endTypeVariables(c, bt, et), |
| 1115 (t) => listener.handleNoTypeVariables(t)); | 1109 (t) => listener.handleNoTypeVariables(t)); |
| 1116 } | 1110 } |
| 1117 | 1111 |
| 1118 /// TODO(ahe): Clean this up. | 1112 /// TODO(ahe): Clean this up. |
| 1119 Token parseStuff(Token token, Function beginStuff, Function stuffParser, | 1113 Token parseStuff(Token token, Function beginStuff, Function stuffParser, |
| 1120 Function endStuff, Function handleNoStuff) { | 1114 Function endStuff, Function handleNoStuff) { |
| 1121 token = _injectGenericCommentTypeList(token); | 1115 token = listener.injectGenericCommentTypeList(token); |
| 1122 if (optional('<', token)) { | 1116 if (optional('<', token)) { |
| 1123 Token begin = token; | 1117 Token begin = token; |
| 1124 beginStuff(begin); | 1118 beginStuff(begin); |
| 1125 int count = 0; | 1119 int count = 0; |
| 1126 do { | 1120 do { |
| 1127 token = stuffParser(token.next); | 1121 token = stuffParser(token.next); |
| 1128 ++count; | 1122 ++count; |
| 1129 } while (optional(',', token)); | 1123 } while (optional(',', token)); |
| 1130 Token next = token.next; | 1124 Token next = token.next; |
| 1131 if (identical(token.stringValue, '>>')) { | 1125 if (identical(token.stringValue, '>>')) { |
| (...skipping 1266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2398 } | 2392 } |
| 2399 | 2393 |
| 2400 Token parseExpressionStatementOrDeclaration(Token token) { | 2394 Token parseExpressionStatementOrDeclaration(Token token) { |
| 2401 if (!inPlainSync && optional("await", token)) { | 2395 if (!inPlainSync && optional("await", token)) { |
| 2402 return parseExpressionStatement(token); | 2396 return parseExpressionStatement(token); |
| 2403 } | 2397 } |
| 2404 assert(token.isIdentifier() || identical(token.stringValue, 'void')); | 2398 assert(token.isIdentifier() || identical(token.stringValue, 'void')); |
| 2405 Token identifier = peekIdentifierAfterType(token); | 2399 Token identifier = peekIdentifierAfterType(token); |
| 2406 if (identifier != null) { | 2400 if (identifier != null) { |
| 2407 assert(identifier.isIdentifier()); | 2401 assert(identifier.isIdentifier()); |
| 2402 |
| 2403 // If the identifier token has a type substitution comment /*=T*/, |
| 2404 // then the set of tokens type tokens should be replaced with the |
| 2405 // tokens parsed from the comment. |
| 2406 token = |
| 2407 listener.replaceTokenWithGenericCommentTypeAssign(token, identifier); |
| 2408 |
| 2408 Token afterId = identifier.next; | 2409 Token afterId = identifier.next; |
| 2409 int afterIdKind = afterId.kind; | 2410 int afterIdKind = afterId.kind; |
| 2410 if (identical(afterIdKind, EQ_TOKEN) || | 2411 if (identical(afterIdKind, EQ_TOKEN) || |
| 2411 identical(afterIdKind, SEMICOLON_TOKEN) || | 2412 identical(afterIdKind, SEMICOLON_TOKEN) || |
| 2412 identical(afterIdKind, COMMA_TOKEN)) { | 2413 identical(afterIdKind, COMMA_TOKEN)) { |
| 2413 // We are looking at "type identifier" followed by '=', ';', ','. | 2414 // We are looking at "type identifier" followed by '=', ';', ','. |
| 2414 return parseVariablesDeclaration(token); | 2415 return parseVariablesDeclaration(token); |
| 2415 } else if (identical(afterIdKind, OPEN_PAREN_TOKEN)) { | 2416 } else if (identical(afterIdKind, OPEN_PAREN_TOKEN)) { |
| 2416 // We are looking at "type identifier '('". | 2417 // We are looking at "type identifier '('". |
| 2417 BeginGroupToken beginParen = afterId; | 2418 BeginGroupToken beginParen = afterId; |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2482 } | 2483 } |
| 2483 } | 2484 } |
| 2484 return parseExpressionStatement(token); | 2485 return parseExpressionStatement(token); |
| 2485 } | 2486 } |
| 2486 | 2487 |
| 2487 Token parseExpressionStatementOrConstDeclaration(Token token) { | 2488 Token parseExpressionStatementOrConstDeclaration(Token token) { |
| 2488 assert(identical(token.stringValue, 'const')); | 2489 assert(identical(token.stringValue, 'const')); |
| 2489 if (isModifier(token.next)) { | 2490 if (isModifier(token.next)) { |
| 2490 return parseVariablesDeclaration(token); | 2491 return parseVariablesDeclaration(token); |
| 2491 } | 2492 } |
| 2493 listener.injectGenericCommentTypeAssign(token.next); |
| 2492 Token identifier = peekIdentifierAfterOptionalType(token.next); | 2494 Token identifier = peekIdentifierAfterOptionalType(token.next); |
| 2493 if (identifier != null) { | 2495 if (identifier != null) { |
| 2494 assert(identifier.isIdentifier()); | 2496 assert(identifier.isIdentifier()); |
| 2495 Token afterId = identifier.next; | 2497 Token afterId = identifier.next; |
| 2496 int afterIdKind = afterId.kind; | 2498 int afterIdKind = afterId.kind; |
| 2497 if (identical(afterIdKind, EQ_TOKEN) || | 2499 if (identical(afterIdKind, EQ_TOKEN) || |
| 2498 identical(afterIdKind, SEMICOLON_TOKEN) || | 2500 identical(afterIdKind, SEMICOLON_TOKEN) || |
| 2499 identical(afterIdKind, COMMA_TOKEN)) { | 2501 identical(afterIdKind, COMMA_TOKEN)) { |
| 2500 // We are looking at "const type identifier" followed by '=', ';', or | 2502 // We are looking at "const type identifier" followed by '=', ';', or |
| 2501 // ','. | 2503 // ','. |
| (...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2790 token = parseArguments(token); | 2792 token = parseArguments(token); |
| 2791 listener.endSend(beginToken, token); | 2793 listener.endSend(beginToken, token); |
| 2792 } else { | 2794 } else { |
| 2793 break; | 2795 break; |
| 2794 } | 2796 } |
| 2795 } | 2797 } |
| 2796 return token; | 2798 return token; |
| 2797 } | 2799 } |
| 2798 | 2800 |
| 2799 Token parsePrimary(Token token, IdentifierContext context) { | 2801 Token parsePrimary(Token token, IdentifierContext context) { |
| 2800 token = _injectGenericCommentTypeList(token); | 2802 token = listener.injectGenericCommentTypeList(token); |
| 2801 final kind = token.kind; | 2803 final kind = token.kind; |
| 2802 if (kind == IDENTIFIER_TOKEN) { | 2804 if (kind == IDENTIFIER_TOKEN) { |
| 2803 return parseSendOrFunctionLiteral(token, context); | 2805 return parseSendOrFunctionLiteral(token, context); |
| 2804 } else if (kind == INT_TOKEN || kind == HEXADECIMAL_TOKEN) { | 2806 } else if (kind == INT_TOKEN || kind == HEXADECIMAL_TOKEN) { |
| 2805 return parseLiteralInt(token); | 2807 return parseLiteralInt(token); |
| 2806 } else if (kind == DOUBLE_TOKEN) { | 2808 } else if (kind == DOUBLE_TOKEN) { |
| 2807 return parseLiteralDouble(token); | 2809 return parseLiteralDouble(token); |
| 2808 } else if (kind == STRING_TOKEN) { | 2810 } else if (kind == STRING_TOKEN) { |
| 2809 return parseLiteralString(token); | 2811 return parseLiteralString(token); |
| 2810 } else if (kind == HASH_TOKEN) { | 2812 } else if (kind == HASH_TOKEN) { |
| (...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3083 listener.beginNewExpression(newKeyword); | 3085 listener.beginNewExpression(newKeyword); |
| 3084 token = parseConstructorReference(token); | 3086 token = parseConstructorReference(token); |
| 3085 token = parseRequiredArguments(token); | 3087 token = parseRequiredArguments(token); |
| 3086 listener.endNewExpression(newKeyword); | 3088 listener.endNewExpression(newKeyword); |
| 3087 return token; | 3089 return token; |
| 3088 } | 3090 } |
| 3089 | 3091 |
| 3090 Token parseConstExpression(Token token) { | 3092 Token parseConstExpression(Token token) { |
| 3091 Token constKeyword = token; | 3093 Token constKeyword = token; |
| 3092 token = expect('const', token); | 3094 token = expect('const', token); |
| 3093 token = _injectGenericCommentTypeList(token); | 3095 token = listener.injectGenericCommentTypeList(token); |
| 3094 final String value = token.stringValue; | 3096 final String value = token.stringValue; |
| 3095 if ((identical(value, '[')) || (identical(value, '[]'))) { | 3097 if ((identical(value, '[')) || (identical(value, '[]'))) { |
| 3096 listener.beginConstLiteral(token); | 3098 listener.beginConstLiteral(token); |
| 3097 listener.handleNoTypeArguments(token); | 3099 listener.handleNoTypeArguments(token); |
| 3098 token = parseLiteralListSuffix(token, constKeyword); | 3100 token = parseLiteralListSuffix(token, constKeyword); |
| 3099 listener.endConstLiteral(token); | 3101 listener.endConstLiteral(token); |
| 3100 return token; | 3102 return token; |
| 3101 } | 3103 } |
| 3102 if (identical(value, '{')) { | 3104 if (identical(value, '{')) { |
| 3103 listener.beginConstLiteral(token); | 3105 listener.beginConstLiteral(token); |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3206 | 3208 |
| 3207 Token parseLiteralNull(Token token) { | 3209 Token parseLiteralNull(Token token) { |
| 3208 listener.handleLiteralNull(token); | 3210 listener.handleLiteralNull(token); |
| 3209 return token.next; | 3211 return token.next; |
| 3210 } | 3212 } |
| 3211 | 3213 |
| 3212 Token parseSend(Token token, IdentifierContext context) { | 3214 Token parseSend(Token token, IdentifierContext context) { |
| 3213 Token beginToken = token; | 3215 Token beginToken = token; |
| 3214 listener.beginSend(token); | 3216 listener.beginSend(token); |
| 3215 token = parseIdentifier(token, context); | 3217 token = parseIdentifier(token, context); |
| 3216 token = _injectGenericCommentTypeList(token); | 3218 token = listener.injectGenericCommentTypeList(token); |
| 3217 if (isValidMethodTypeArguments(token)) { | 3219 if (isValidMethodTypeArguments(token)) { |
| 3218 token = parseTypeArgumentsOpt(token); | 3220 token = parseTypeArgumentsOpt(token); |
| 3219 } else { | 3221 } else { |
| 3220 listener.handleNoTypeArguments(token); | 3222 listener.handleNoTypeArguments(token); |
| 3221 } | 3223 } |
| 3222 token = parseArgumentsOpt(token); | 3224 token = parseArgumentsOpt(token); |
| 3223 listener.endSend(beginToken, token); | 3225 listener.endSend(beginToken, token); |
| 3224 return token; | 3226 return token; |
| 3225 } | 3227 } |
| 3226 | 3228 |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3312 | 3314 |
| 3313 Token parseVariablesDeclarationNoSemicolon(Token token) { | 3315 Token parseVariablesDeclarationNoSemicolon(Token token) { |
| 3314 // Only called when parsing a for loop, so this is for parsing locals. | 3316 // Only called when parsing a for loop, so this is for parsing locals. |
| 3315 return parseVariablesDeclarationMaybeSemicolon(token, false); | 3317 return parseVariablesDeclarationMaybeSemicolon(token, false); |
| 3316 } | 3318 } |
| 3317 | 3319 |
| 3318 Token parseVariablesDeclarationMaybeSemicolon( | 3320 Token parseVariablesDeclarationMaybeSemicolon( |
| 3319 Token token, bool endWithSemicolon) { | 3321 Token token, bool endWithSemicolon) { |
| 3320 int count = 1; | 3322 int count = 1; |
| 3321 token = parseMetadataStar(token); | 3323 token = parseMetadataStar(token); |
| 3324 |
| 3325 // If the next token has a type substitution comment /*=T*/, then |
| 3326 // the current 'var' token should be repealed and replaced. |
| 3327 if (identical('var', token.stringValue)) { |
| 3328 token = |
| 3329 listener.replaceTokenWithGenericCommentTypeAssign(token, token.next); |
| 3330 } |
| 3331 |
| 3322 token = parseModifiers(token); | 3332 token = parseModifiers(token); |
| 3323 token = parseTypeOpt(token); | 3333 token = parseTypeOpt(token); |
| 3324 listener.beginVariablesDeclaration(token); | 3334 listener.beginVariablesDeclaration(token); |
| 3325 token = parseOptionallyInitializedIdentifier(token); | 3335 token = parseOptionallyInitializedIdentifier(token); |
| 3326 while (optional(',', token)) { | 3336 while (optional(',', token)) { |
| 3327 token = parseOptionallyInitializedIdentifier(token.next); | 3337 token = parseOptionallyInitializedIdentifier(token.next); |
| 3328 ++count; | 3338 ++count; |
| 3329 } | 3339 } |
| 3330 if (endWithSemicolon) { | 3340 if (endWithSemicolon) { |
| 3331 Token semicolon = token; | 3341 Token semicolon = token; |
| (...skipping 472 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3804 Token token, FastaCode<TokenArgument> code) { | 3814 Token token, FastaCode<TokenArgument> code) { |
| 3805 return reportUnrecoverableError( | 3815 return reportUnrecoverableError( |
| 3806 token, () => code.format(uri, token.charOffset, token)); | 3816 token, () => code.format(uri, token.charOffset, token)); |
| 3807 } | 3817 } |
| 3808 | 3818 |
| 3809 Token reportUnrecoverableErrorCodeWithString( | 3819 Token reportUnrecoverableErrorCodeWithString( |
| 3810 Token token, FastaCode<StringArgument> code, String string) { | 3820 Token token, FastaCode<StringArgument> code, String string) { |
| 3811 return reportUnrecoverableError( | 3821 return reportUnrecoverableError( |
| 3812 token, () => code.format(uri, token.charOffset, string)); | 3822 token, () => code.format(uri, token.charOffset, string)); |
| 3813 } | 3823 } |
| 3814 | |
| 3815 /// Matches a generic comment type parameters or type arguments and injects | |
| 3816 /// them into the token stream before the given [token]. | |
| 3817 Token _injectGenericCommentTypeList(Token token) { | |
| 3818 return _injectGenericComment(token, GENERIC_METHOD_TYPE_LIST, 2); | |
| 3819 } | |
| 3820 | |
| 3821 /// Check if the given [token] has a comment token with the given [info], | |
| 3822 /// which should be either [GENERIC_METHOD_TYPE_ASSIGN] or | |
| 3823 /// [GENERIC_METHOD_TYPE_LIST]. If found, parse the comment into tokens and | |
| 3824 /// inject into the token stream before the [token]. | |
| 3825 Token _injectGenericComment(Token token, PrecedenceInfo info, int prefixLen) { | |
| 3826 if (parseGenericMethodComments) { | |
| 3827 CommentToken t = token.precedingCommentTokens; | |
| 3828 for (; t != null; t = t.next) { | |
| 3829 if (t.info == info) { | |
| 3830 String code = t.lexeme.substring(prefixLen, t.lexeme.length - 2); | |
| 3831 Token tokens = _scanGenericMethodComment(code, t.offset + prefixLen); | |
| 3832 if (tokens != null) { | |
| 3833 // Remove the token from the comment stream. | |
| 3834 t.remove(); | |
| 3835 // Insert the tokens into the stream. | |
| 3836 _injectTokenList(token, tokens); | |
| 3837 return tokens; | |
| 3838 } | |
| 3839 } | |
| 3840 } | |
| 3841 } | |
| 3842 return token; | |
| 3843 } | |
| 3844 | |
| 3845 /// Scans the given [code], and returns the tokens, otherwise returns `null`. | |
| 3846 Token _scanGenericMethodComment(String code, int offset) { | |
| 3847 var scanner = new SubStringScanner(offset, code); | |
| 3848 Token firstToken = scanner.tokenize(); | |
| 3849 if (scanner.hasErrors) { | |
| 3850 return null; | |
| 3851 } | |
| 3852 return firstToken; | |
| 3853 } | |
| 3854 | |
| 3855 void _injectTokenList(Token beforeToken, Token firstToken) { | |
| 3856 // Scanner creates a cyclic EOF token. | |
| 3857 Token lastToken = firstToken; | |
| 3858 while (lastToken.next.info != EOF_INFO) { | |
| 3859 lastToken = lastToken.next; | |
| 3860 } | |
| 3861 // Inject these new tokens into the stream. | |
| 3862 Token previous = beforeToken.previous; | |
| 3863 lastToken.setNext(beforeToken); | |
| 3864 previous.setNext(firstToken); | |
| 3865 beforeToken = firstToken; | |
| 3866 } | |
| 3867 } | 3824 } |
| 3868 | 3825 |
| 3869 typedef FastaMessage NoArgument(Uri uri, int charOffset); | 3826 typedef FastaMessage NoArgument(Uri uri, int charOffset); |
| 3870 | 3827 |
| 3871 typedef FastaMessage TokenArgument(Uri uri, int charOffset, Token token); | 3828 typedef FastaMessage TokenArgument(Uri uri, int charOffset, Token token); |
| 3872 | 3829 |
| 3873 typedef FastaMessage StringArgument(Uri uri, int charOffset, String string); | 3830 typedef FastaMessage StringArgument(Uri uri, int charOffset, String string); |
| OLD | NEW |