Index: pkg/front_end/lib/src/fasta/parser/parser.dart |
diff --git a/pkg/front_end/lib/src/fasta/parser/parser.dart b/pkg/front_end/lib/src/fasta/parser/parser.dart |
index f323b4519c356cb29e55355deacd0e461ec1286a..229b72eaf4c8bf1c97a1eea4ccc7931af8f9b5a5 100644 |
--- a/pkg/front_end/lib/src/fasta/parser/parser.dart |
+++ b/pkg/front_end/lib/src/fasta/parser/parser.dart |
@@ -726,6 +726,7 @@ class Parser { |
// Function type without return type. |
return parseType(token); |
} |
+ token = _injectGenericCommentTypeAssign(token); |
ahe
2017/04/06 08:58:38
Methods in the parser needs to be public so they c
ahe
2017/04/06 10:04:42
See CL 2799043004 for a detailed explanation.
scheglov
2017/04/06 16:15:55
I moved these methods to Listener.
|
Token peek = peekAfterIfType(token); |
if (peek != null && (peek.isIdentifier() || optional('this', peek))) { |
return parseType(token); |
@@ -2405,6 +2406,12 @@ class Parser { |
Token identifier = peekIdentifierAfterType(token); |
if (identifier != null) { |
assert(identifier.isIdentifier()); |
+ |
+ // If the identifier token has a type substitution comment /*=T*/, |
+ // then the set of tokens type tokens should be replaced with the |
+ // tokens parsed from the comment. |
+ token = _replaceTokenWithGenericCommentTypeAssign(token, identifier); |
+ |
Token afterId = identifier.next; |
int afterIdKind = afterId.kind; |
if (identical(afterIdKind, EQ_TOKEN) || |
@@ -2489,6 +2496,7 @@ class Parser { |
if (isModifier(token.next)) { |
return parseVariablesDeclaration(token); |
} |
+ _injectGenericCommentTypeAssign(token.next); |
Token identifier = peekIdentifierAfterOptionalType(token.next); |
if (identifier != null) { |
assert(identifier.isIdentifier()); |
@@ -3310,6 +3318,13 @@ class Parser { |
Token token, bool endWithSemicolon) { |
int count = 1; |
token = parseMetadataStar(token); |
+ |
+ // If the next token has a type substitution comment /*=T*/, then |
+ // the current 'var' token should be repealed and replaced. |
+ if (token.keyword == Keyword.VAR) { |
ahe
2017/04/06 08:58:38
Use this method to match keywords:
optional('var'
ahe
2017/04/06 10:04:42
See lines 178-184.
scheglov
2017/04/06 16:15:55
Done.
|
+ token = _replaceTokenWithGenericCommentTypeAssign(token, token.next); |
+ } |
+ |
token = parseModifiers(token); |
token = parseTypeOpt(token); |
listener.beginVariablesDeclaration(token); |
@@ -3803,6 +3818,12 @@ class Parser { |
token, () => code.format(uri, token.charOffset, string)); |
} |
+ /// Matches a generic comment type substitution and injects it into the token |
+ /// stream before the given [token]. |
+ Token _injectGenericCommentTypeAssign(Token token) { |
+ return _injectGenericComment(token, GENERIC_METHOD_TYPE_ASSIGN, 3); |
+ } |
+ |
/// Matches a generic comment type parameters or type arguments and injects |
/// them into the token stream before the given [token]. |
Token _injectGenericCommentTypeList(Token token) { |
@@ -3855,6 +3876,23 @@ class Parser { |
previous.setNext(firstToken); |
beforeToken = firstToken; |
} |
+ |
+ /// If the [tokenWithComment] has a type substitution comment /*=T*/, then |
+ /// the comment should be scanned into new tokens, and these tokens inserted |
+ /// instead of tokens from the [tokenToStartReplacing] to the |
+ /// [tokenWithComment]. Returns the first newly inserted token, or the |
+ /// original [tokenWithComment]. |
+ Token _replaceTokenWithGenericCommentTypeAssign( |
+ Token tokenToStartReplacing, Token tokenWithComment) { |
+ Token injected = _injectGenericCommentTypeAssign(tokenWithComment); |
+ if (!identical(injected, tokenWithComment)) { |
+ Token prev = tokenToStartReplacing.previous; |
+ prev.setNextWithoutSettingPrevious(injected); |
+ tokenToStartReplacing = injected; |
+ tokenToStartReplacing.previous = prev; |
+ } |
+ return tokenToStartReplacing; |
+ } |
} |
typedef FastaMessage NoArgument(Uri uri, int charOffset); |