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 0a8d68d77a76cdf7aefdbda26dade47234441bb1..1787e1175c4aa5e40f634ee48387b945ab7c2ad0 100644 |
| --- a/pkg/compiler/lib/src/parser/parser.dart |
| +++ b/pkg/compiler/lib/src/parser/parser.dart |
| @@ -463,6 +463,11 @@ class Parser { |
| } |
| token = parseIdentifier(token); |
| if (optional('(', token)) { |
| + listener.handleNoTypeVariables(token); |
| + token = parseFormalParameters(token); |
| + listener.handleFunctionTypedFormalParameter(token); |
| + } else if (enableGenericMethodSyntax && optional('<', token)) { |
| + token = parseTypeVariablesOpt(token); |
| token = parseFormalParameters(token); |
| listener.handleFunctionTypedFormalParameter(token); |
| } |
| @@ -767,12 +772,15 @@ class Parser { |
| Token parseTypeVariable(Token token) { |
| listener.beginTypeVariable(token); |
| token = parseIdentifier(token); |
| - if (optional('extends', token)) { |
| + Token extendsOrSuper = null; |
| + if (optional('extends', token) || |
| + (enableGenericMethodSyntax && optional('super', token))) { |
| + extendsOrSuper = token; |
| token = parseType(token.next); |
| } else { |
| listener.handleNoType(token); |
| } |
| - listener.endTypeVariable(token); |
| + listener.endTypeVariable(token, extendsOrSuper); |
| return token; |
| } |
| @@ -1845,15 +1853,37 @@ class Parser { |
| // We are looking at "type identifier '('". |
| BeginGroupToken beginParen = afterId; |
| Token endParen = beginParen.endGroup; |
| + // TODO(eernst): Check for NPE as described in issue 26252. |
| Token afterParens = endParen.next; |
| if (optional('{', afterParens) || |
| optional('=>', afterParens) || |
| optional('async', afterParens) || |
| optional('sync', afterParens)) { |
| // We are looking at "type identifier '(' ... ')'" followed |
| - // by '=>' or '{'. |
| + // by '{', '=>', 'async', or 'sync'. |
| return parseFunctionDeclaration(token); |
| } |
| + } else if (enableGenericMethodSyntax && |
| + identical(afterIdKind, LT_TOKEN)) { |
| + // We are looking at "type identifier '<'". |
| + BeginGroupToken beginAngle = afterId; |
| + Token endAngle = beginAngle.endGroup; |
| + if (endAngle != null && |
| + identical(endAngle.next.kind, OPEN_PAREN_TOKEN)) { |
| + BeginGroupToken beginParen = endAngle.next; |
| + Token endParen = beginParen.endGroup; |
| + if (endParen != null) { |
| + Token afterParens = endParen.next; |
| + if (optional('{', afterParens) || |
| + optional('=>', afterParens) || |
| + optional('async', afterParens) || |
| + optional('sync', afterParens)) { |
| + // We are looking at "type identifier '<' ... '>' '(' ... ')'" |
| + // followed by '{', '=>', 'async', or 'sync'. |
| + return parseFunctionDeclaration(token); |
| + } |
| + } |
| + } |
| } |
| // Fall-through to expression statement. |
| } else { |
| @@ -1861,6 +1891,7 @@ class Parser { |
| return parseLabeledStatement(token); |
| } else if (optional('(', token.next)) { |
| BeginGroupToken begin = token.next; |
| + // TODO(eernst): Check for NPE as described in issue 26252. |
| String afterParens = begin.endGroup.next.stringValue; |
| if (identical(afterParens, '{') || |
| identical(afterParens, '=>') || |
| @@ -1868,6 +1899,24 @@ class Parser { |
| identical(afterParens, 'sync')) { |
| return parseFunctionDeclaration(token); |
| } |
| + } else if (enableGenericMethodSyntax && optional('<', token.next)) { |
| + BeginGroupToken beginAngle = token.next; |
| + Token endAngle = beginAngle.endGroup; |
| + if (endAngle != null && |
| + identical(endAngle.next.kind, OPEN_PAREN_TOKEN)) { |
| + BeginGroupToken beginParen = endAngle.next; |
| + Token endParen = beginParen.endGroup; |
| + if (endParen != null) { |
| + String afterParens = endParen.next.stringValue; |
| + if (identical(afterParens, '{') || |
| + identical(afterParens, '=>') || |
| + identical(afterParens, 'async') || |
| + identical(afterParens, 'sync')) { |
| + return parseFunctionDeclaration(token); |
| + } |
| + } |
| + } |
| + // Fall through to expression statement. |
| } |
| } |
| return parseExpressionStatement(token); |
| @@ -2135,11 +2184,14 @@ class Parser { |
| } |
| } else if (kind == OPEN_PAREN_TOKEN) { |
| return parseParenthesizedExpressionOrFunctionLiteral(token); |
| - } else if ((kind == LT_TOKEN) || |
| - (kind == OPEN_SQUARE_BRACKET_TOKEN) || |
| - (kind == OPEN_CURLY_BRACKET_TOKEN) || |
| - token.stringValue == '[]') { |
| - return parseLiteralListOrMap(token); |
| + } else if (kind == OPEN_SQUARE_BRACKET_TOKEN || token.stringValue == '[]') { |
| + listener.handleNoTypeArguments(token); |
| + return parseLiteralListSuffix(token, null); |
| + } else if (kind == OPEN_CURLY_BRACKET_TOKEN) { |
| + listener.handleNoTypeArguments(token); |
| + return parseLiteralMapSuffix(token, null); |
| + } else if (kind == LT_TOKEN) { |
| + return parseLiteralListOrMapOrFunction(token, null); |
| } else { |
| return listener.expectedExpression(token); |
| } |
| @@ -2147,6 +2199,7 @@ class Parser { |
| Token parseParenthesizedExpressionOrFunctionLiteral(Token token) { |
| BeginGroupToken beginGroup = token; |
| + // TODO(eernst): Check for NPE as described in issue 26252. |
| Token nextToken = beginGroup.endGroup.next; |
| int kind = nextToken.kind; |
| if (mayParseFunctionExpressions && |
| @@ -2154,6 +2207,7 @@ class Parser { |
| identical(kind, OPEN_CURLY_BRACKET_TOKEN) || |
| (identical(kind, KEYWORD_TOKEN) && |
| (nextToken.value == 'async' || nextToken.value == 'sync')))) { |
| + listener.handleNoTypeVariables(token); |
| return parseUnnamedFunction(token); |
| } else { |
| bool old = mayParseFunctionExpressions; |
| @@ -2203,47 +2257,102 @@ class Parser { |
| return token; |
| } |
| - Token parseLiteralListOrMap(Token token) { |
| - Token constKeyword = null; |
| - if (optional('const', token)) { |
| - constKeyword = token; |
| - token = token.next; |
| - } |
| - token = parseTypeArgumentsOpt(token); |
| + // '[' (expression (',' expression))? ']'. |
| + // Provide [constKeyword] if preceded by 'const', null if not. |
| + // This is a suffix parser because it is assumed that type arguments have |
| + // been parsed, or `listener.handleNoTypeArguments(..)` has been executed. |
| + Token parseLiteralListSuffix(Token token, Token constKeyword) { |
| Token beginToken = token; |
|
Johnni Winther
2016/04/14 08:23:50
You can assert that token is '[' or '[]' here.
eernst
2016/04/14 09:47:27
Done.
|
| int count = 0; |
| - if (optional('{', token)) { |
| + if (optional('[', token)) { |
| bool old = mayParseFunctionExpressions; |
| mayParseFunctionExpressions = true; |
| do { |
| - if (optional('}', token.next)) { |
| + if (optional(']', token.next)) { |
| token = token.next; |
| break; |
| } |
| - token = parseMapLiteralEntry(token.next); |
| + token = parseExpression(token.next); |
| ++count; |
| } while (optional(',', token)); |
| mayParseFunctionExpressions = old; |
| - listener.handleLiteralMap(count, beginToken, constKeyword, token); |
| - return expect('}', token); |
| - } else if (optional('[', token)) { |
| + listener.handleLiteralList(count, beginToken, constKeyword, token); |
| + return expect(']', token); |
| + } else if (optional('[]', token)) { |
| + listener.handleLiteralList(0, token, constKeyword, token); |
| + return token.next; |
| + } |
| + listener.unexpected(token); |
| + return null; |
| + } |
| + |
| + // '{' expression (',' expression) '}'. |
| + // Provide token for [constKeyword] if preceded by 'const', null if not. |
| + // This is a suffix parser because it is assumed that type arguments have |
| + // been parsed, or `listener.handleNoTypeArguments(..)` has been executed. |
| + Token parseLiteralMapSuffix(Token token, Token constKeyword) { |
| + Token beginToken = token; |
|
Johnni Winther
2016/04/14 08:23:50
You can assert that token is '{' here.
eernst
2016/04/14 09:47:27
Done.
|
| + int count = 0; |
| + if (optional('{', token)) { |
| bool old = mayParseFunctionExpressions; |
| mayParseFunctionExpressions = true; |
| do { |
| - if (optional(']', token.next)) { |
| + if (optional('}', token.next)) { |
| token = token.next; |
| break; |
| } |
| - token = parseExpression(token.next); |
| + token = parseMapLiteralEntry(token.next); |
| ++count; |
| } while (optional(',', token)); |
| mayParseFunctionExpressions = old; |
| - listener.handleLiteralList(count, beginToken, constKeyword, token); |
| - return expect(']', token); |
| - } else if (optional('[]', token)) { |
| - listener.handleLiteralList(0, token, constKeyword, token); |
| - return token.next; |
| + listener.handleLiteralMap(count, beginToken, constKeyword, token); |
| + return expect('}', token); |
| + } |
| + listener.unexpected(token); |
| + return null; |
| + } |
| + |
| + // '(' (argument (',' argument)*)? ')' body. |
| + // This is a suffix parser because it is assumed that type arguments have |
| + // been parsed, or `listener.handleNoTypeArguments(..)` has been executed. |
| + Token parseLiteralFunctionSuffix(Token token) { |
| + if (optional('(',token)) { |
|
Johnni Winther
2016/04/14 08:23:50
You can assert that token is '(' here.
eernst
2016/04/14 09:47:27
Done.
|
| + BeginGroupToken beginGroup = token; |
| + if (beginGroup.endGroup != null) { |
| + Token nextToken = beginGroup.endGroup.next; |
| + int kind = nextToken.kind; |
| + if (identical(kind, FUNCTION_TOKEN) || |
| + identical(kind, OPEN_CURLY_BRACKET_TOKEN) || |
| + (identical(kind, KEYWORD_TOKEN) && |
| + (nextToken.value == 'async' || nextToken.value == 'sync'))) { |
| + return parseUnnamedFunction(token); |
| + } |
| + // Fall through. |
| + } |
| + // Fall through. |
| + } |
| + listener.unexpected(token); |
| + return null; |
| + } |
| + |
| + // typeArguments (literalList | literalMap | unnamedFunction). |
| + // Provide token for [constKeyword] if preceded by 'const', null if not. |
| + Token parseLiteralListOrMapOrFunction(Token token, Token constKeyword) { |
| + assert(optional('<', token)); |
| + BeginGroupToken begin = token; |
| + if (enableGenericMethodSyntax && |
| + constKeyword == null && |
| + begin.endGroup != null && |
| + identical(begin.endGroup.next.kind, OPEN_PAREN_TOKEN)) { |
| + token = parseTypeVariablesOpt(token); |
| + return parseLiteralFunctionSuffix(token); |
| } else { |
| + token = parseTypeArgumentsOpt(token); |
| + if (optional('{', token)) { |
| + return parseLiteralMapSuffix(token, constKeyword); |
| + } else if ((optional('[', token)) || (optional('[]', token))) { |
| + return parseLiteralListSuffix(token, constKeyword); |
| + } |
| listener.unexpected(token); |
| return null; |
| } |
| @@ -2275,8 +2384,14 @@ class Parser { |
| } |
| bool isFunctionDeclaration(Token token) { |
| + if (enableGenericMethodSyntax && optional('<', token)) { |
| + BeginGroupToken begin = token; |
| + if (begin.endGroup == null) return false; |
| + token = begin.endGroup.next; |
| + } |
| if (optional('(', token)) { |
| BeginGroupToken begin = token; |
| + // TODO(eernst): Check for NPE as described in issue 26252. |
| String afterParens = begin.endGroup.next.stringValue; |
| if (identical(afterParens, '{') || |
| identical(afterParens, '=>') || |
| @@ -2311,11 +2426,16 @@ class Parser { |
| Token constKeyword = token; |
| token = expect('const', token); |
| final String value = token.stringValue; |
| - if ((identical(value, '<')) || |
| - (identical(value, '[')) || |
| - (identical(value, '[]')) || |
| - (identical(value, '{'))) { |
| - return parseLiteralListOrMap(constKeyword); |
| + if ((identical(value, '[')) || (identical(value, '[]'))) { |
| + listener.handleNoTypeArguments(token); |
| + return parseLiteralListSuffix(token, constKeyword); |
| + } |
| + if (identical(value, '{')) { |
| + listener.handleNoTypeArguments(token); |
| + return parseLiteralMapSuffix(token, constKeyword); |
| + } |
| + if (identical(value, '<')) { |
| + return parseLiteralListOrMapOrFunction(token, constKeyword); |
| } |
| token = parseConstructorReference(token); |
| token = parseRequiredArguments(token); |