Chromium Code Reviews| Index: pkg/compiler/lib/src/parser/parser.dart |
| diff --git a/pkg/compiler/lib/src/parser/parser.dart b/pkg/compiler/lib/src/parser/parser.dart |
| index 80e6de224e45c5fdb06da3c0743ddd3477add81b..93a696552f27493e427c54a2f4aa00287d7fc62b 100644 |
| --- a/pkg/compiler/lib/src/parser/parser.dart |
| +++ b/pkg/compiler/lib/src/parser/parser.dart |
| @@ -41,6 +41,8 @@ import '../tokens/token_constants.dart' show |
| EOF_TOKEN, |
| EQ_TOKEN, |
| FUNCTION_TOKEN, |
| + GT_TOKEN, |
| + GT_GT_TOKEN, |
| HASH_TOKEN, |
| HEXADECIMAL_TOKEN, |
| IDENTIFIER_TOKEN, |
| @@ -103,8 +105,12 @@ class Parser { |
| bool mayParseFunctionExpressions = true; |
| bool asyncAwaitKeywordsEnabled; |
| - Parser(this.listener, this.parserOptions, |
| - {this.asyncAwaitKeywordsEnabled: false}); |
| + final bool _enableGenericMethodSyntax; |
|
ahe
2016/04/08 09:53:33
Please avoid private fields, a subclass outside th
eernst
2016/04/08 17:07:10
I'm not sure what the right approach would be here
|
| + |
| + Parser(this.listener, ParserOptions _parserOptions, |
|
ahe
2016/04/08 09:53:32
Remove _ from parameter.
eernst
2016/04/08 17:07:10
Done.
|
| + {this.asyncAwaitKeywordsEnabled: false}) : |
| + parserOptions = _parserOptions, |
|
ahe
2016/04/08 09:53:32
In:
parserOption = parserOptions
The left-hand
eernst
2016/04/08 17:07:10
Acknowledged.
|
| + _enableGenericMethodSyntax = _parserOptions.enableGenericMethodSyntax; |
| Token parseUnit(Token token) { |
| listener.beginCompilationUnit(token); |
| @@ -525,6 +531,83 @@ class Parser { |
| return false; |
| } |
| + /// Checks for '<' type (',' type)* '>', returns null iff failing. |
|
ahe
2016/04/08 09:53:32
Avoid using academic short-hand and notation in do
ahe
2016/04/08 09:53:33
How about:
Returns next token after match token i
eernst
2016/04/08 17:07:10
Done.
|
| + /// Does not produce listener events. In this case the final '>' may be |
| + /// the first character in a '>>' token, in which case the `endGroup` of |
| + /// the initial '<' will be null, so we cannot rely on `endGroup`. |
| + Token tryParseTypeArgumentsNested(Token token) { |
|
ahe
2016/04/08 09:53:32
Below I question if this method is necessary. Howe
eernst
2016/04/08 17:07:10
The old (abandoned) CL did express the same distin
|
| + final kind = token.kind; |
|
ahe
2016/04/08 09:53:33
Remove this variable. It's confusing that token is
eernst
2016/04/08 17:07:11
Done.
|
| + if (!identical(kind, LT_TOKEN)) return null; |
| + token = token.next; |
| + if (token == null) return null; |
| + token = tryParseType(token); |
| + while (token != null && identical(token.kind, COMMA_TOKEN)) { |
| + token = token.next; |
| + if (token == null) return null; |
| + token = tryParseType(token); |
| + } |
| + if (token == null) return null; |
| + if (identical(token.kind, GT_TOKEN)) return token.next; |
| + if (!identical(token.kind, GT_GT_TOKEN)) return null; |
| + // [token] is '>>' of which the final '>' that we are parsing is the first |
| + // character. In order to keep the parsing process on track we must return |
| + // a synthetic '>' corresponding to the second character of that '>>'. |
| + Token syntheticToken = new SymbolToken(GT_INFO, token.charOffset + 1); |
| + syntheticToken.next = token.next; |
| + return syntheticToken; |
| + } |
| + |
| + /// Checks for identifier ('.' identifier)?, returns null iff failing. |
|
ahe
2016/04/08 09:53:33
iff -> if.
What does "failing" mean? How about:
eernst
2016/04/08 17:07:10
Rephrased in a similar manner as several earlier d
|
| + /// Does not produce listener events. |
| + Token tryParseQualified(Token token) { |
|
ahe
2016/04/08 09:53:32
There's probably suboptimal error recovery here. F
eernst
2016/04/08 17:07:10
It would be nice if they _could_ do that. ;)
For
|
| + if (!identical(token.kind, IDENTIFIER_TOKEN)) return null; |
| + token = token.next; |
| + if (!identical(token.kind, PERIOD_TOKEN)) return token; |
| + token = token.next; |
| + if (!identical(token.kind, IDENTIFIER_TOKEN)) return null; |
| + return token.next; |
| + } |
| + |
| + /// Checks for typeName typeArguments? and returns null iff failing. |
|
ahe
2016/04/08 09:53:32
iff -> if, but what about:
Returns next token aft
eernst
2016/04/08 17:07:11
Rephrased in a similar manner as several earlier d
|
| + /// Does not produce listener events. |
| + Token tryParseType(Token token) { |
| + token = tryParseQualified(token); |
| + if (token == null) return null; |
| + Token tokenAfterQualified = token; |
| + token = tryParseTypeArgumentsNested(token); |
| + return token == null ? tokenAfterQualified : token; |
| + } |
| + |
| + /// Checks for '<' type (',' type)* '>' '(' and returns null iff failing. |
|
ahe
2016/04/08 09:53:33
iff -> if, but what about:
Returns last token of
eernst
2016/04/08 17:07:10
Rephrased in a similar manner as several earlier d
|
| + /// Does not produce listener events. With respect to the final '(', please |
| + /// see the description of [isValidTypeArguments]. |
| + Token tryParseTypeArguments(Token token) { |
| + final kind = token.kind; |
| + if (!identical(kind, LT_TOKEN)) return null; |
| + BeginGroupToken beginToken = token; |
| + Token endToken = beginToken.endGroup; |
| + token = token.next; |
| + if (token == null || endToken == null || |
| + !identical(endToken.next?.kind, OPEN_PAREN_TOKEN)) return null; |
| + token = tryParseType(token); |
|
ahe
2016/04/08 09:53:32
Is this really necessary? If so, perhaps push back
|
| + while (token != null && identical(token.kind, COMMA_TOKEN)) { |
| + token = token.next; |
| + if (token == null) return null; |
| + token = tryParseType(token); |
| + } |
| + if (!identical(token?.kind, GT_TOKEN)) return null; |
| + return token.next; |
| + } |
| + |
| + /// Returns true iff the tokens starting from [token] match |
|
ahe
2016/04/08 09:53:32
iff->if.
We normally emit "otherwise returns fals
eernst
2016/04/08 17:07:10
Rephrased in a similar manner as several earlier d
|
| + /// '<' type (',' type)* '>' '('. The final '(' is not part of the |
| + /// grammar construct `typeArguments`, but it is required here such that |
| + /// type arguments in generic method invocations can be recognized, and |
| + /// as few as possible other constructs will pass (e.g., 'a < C, D > 3'). |
| + bool isValidTypeArguments(Token token) { |
|
ahe
2016/04/08 09:53:32
Rename to "isValidMethodTypeArguments" to signal t
eernst
2016/04/08 17:07:10
Makes sense, done. (This deviates from the naming
floitsch
2016/04/11 11:00:13
Fwiw, this CL only adds syntactic support. The sem
|
| + return tryParseTypeArguments(token) != null; |
| + } |
|
ahe
2016/04/08 09:53:32
Please reverse the order of all these methods. It'
eernst
2016/04/08 17:07:10
Ah, that's funny. The literate programming credo (
|
| + |
| Token parseQualified(Token token) { |
| token = parseIdentifier(token); |
| while (optional('.', token)) { |
| @@ -1011,6 +1094,11 @@ class Parser { |
| } |
| Token token = parseIdentifier(name); |
| + if (_enableGenericMethodSyntax && getOrSet == null) { |
| + token = parseTypeVariablesOpt(token); |
| + } else { |
| + listener.handleNoTypeVariables(token); |
| + } |
| token = parseFormalParametersOpt(token); |
| bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; |
| token = parseAsyncModifier(token); |
| @@ -1319,7 +1407,8 @@ class Parser { |
| // error handling. |
| final String value = token.stringValue; |
| if ((identical(value, '(')) || (identical(value, '.')) |
| - || (identical(value, '{')) || (identical(value, '=>'))) { |
| + || (identical(value, '{')) || (identical(value, '=>')) |
| + || (_enableGenericMethodSyntax && identical(value, '<'))) { |
| isField = false; |
| break; |
| } else if (identical(value, ';')) { |
| @@ -1420,6 +1509,11 @@ class Parser { |
| } |
| token = parseQualifiedRestOpt(token); |
| + if (_enableGenericMethodSyntax && getOrSet == null) { |
| + token = parseTypeVariablesOpt(token); |
| + } else { |
| + listener.handleNoTypeVariables(token); |
| + } |
| token = parseFormalParametersOpt(token); |
| token = parseInitializersOpt(token); |
| bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; |
| @@ -1506,6 +1600,11 @@ class Parser { |
| } |
| token = parseQualifiedRestOpt(token); |
| listener.endFunctionName(token); |
| + if (_enableGenericMethodSyntax && getOrSet == null) { |
| + token = parseTypeVariablesOpt(token); |
| + } else { |
| + listener.handleNoTypeVariables(token); |
| + } |
| token = parseFormalParametersOpt(token); |
| token = parseInitializersOpt(token); |
| bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; |
| @@ -1546,6 +1645,11 @@ class Parser { |
| listener.beginFunctionName(token); |
| token = parseIdentifier(token); |
| listener.endFunctionName(token); |
| + if (_enableGenericMethodSyntax) { |
| + token = parseTypeVariablesOpt(token); |
| + } else { |
| + listener.handleNoTypeVariables(token); |
| + } |
| token = parseFormalParameters(token); |
| listener.handleNoInitializers(); |
| bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; |
| @@ -2011,6 +2115,7 @@ class Parser { |
| listener.handleIndexedExpression(openSquareBracket, token); |
| token = expect(']', token); |
| } else if (optional('(', token)) { |
| + listener.handleNoTypeArguments(token); |
| token = parseArguments(token); |
| listener.endSend(token); |
| } else { |
| @@ -2108,6 +2213,7 @@ class Parser { |
| token = token.next; |
| if (optional('(', token)) { |
| // Constructor forwarding. |
| + listener.handleNoTypeArguments(token); |
| token = parseArguments(token); |
| listener.endSend(token); |
| } |
| @@ -2119,6 +2225,7 @@ class Parser { |
| token = token.next; |
| if (optional('(', token)) { |
| // Super constructor. |
| + listener.handleNoTypeArguments(token); |
| token = parseArguments(token); |
| listener.endSend(token); |
| } |
| @@ -2335,6 +2442,11 @@ class Parser { |
| Token parseSend(Token token) { |
| listener.beginSend(token); |
| token = parseIdentifier(token); |
| + if (_enableGenericMethodSyntax && isValidTypeArguments(token)) { |
| + token = parseTypeArgumentsOpt(token); |
| + } else { |
| + listener.handleNoTypeArguments(token); |
| + } |
| token = parseArgumentsOpt(token); |
| listener.endSend(token); |
| return token; |