| 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..f4fbd9d5c1d110c7d360c614075dde72a972a62b 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,30 +2257,16 @@ class Parser {
|
| return token;
|
| }
|
|
|
| - Token parseLiteralListOrMap(Token token) {
|
| - Token constKeyword = null;
|
| - if (optional('const', token)) {
|
| - constKeyword = token;
|
| - token = token.next;
|
| - }
|
| - token = parseTypeArgumentsOpt(token);
|
| + /// '[' (expressionList ','?)? ']'.
|
| + ///
|
| + /// 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) {
|
| + assert(optional('[', token) || optional('[]', token));
|
| Token beginToken = token;
|
| int count = 0;
|
| - if (optional('{', token)) {
|
| - bool old = mayParseFunctionExpressions;
|
| - mayParseFunctionExpressions = true;
|
| - do {
|
| - if (optional('}', token.next)) {
|
| - token = token.next;
|
| - break;
|
| - }
|
| - token = parseMapLiteralEntry(token.next);
|
| - ++count;
|
| - } while (optional(',', token));
|
| - mayParseFunctionExpressions = old;
|
| - listener.handleLiteralMap(count, beginToken, constKeyword, token);
|
| - return expect('}', token);
|
| - } else if (optional('[', token)) {
|
| + if (optional('[', token)) {
|
| bool old = mayParseFunctionExpressions;
|
| mayParseFunctionExpressions = true;
|
| do {
|
| @@ -2240,10 +2280,80 @@ class Parser {
|
| mayParseFunctionExpressions = old;
|
| listener.handleLiteralList(count, beginToken, constKeyword, token);
|
| return expect(']', token);
|
| - } else if (optional('[]', token)) {
|
| - listener.handleLiteralList(0, token, constKeyword, token);
|
| - return token.next;
|
| + }
|
| + // Looking at '[]'.
|
| + listener.handleLiteralList(0, token, constKeyword, token);
|
| + return token.next;
|
| + }
|
| +
|
| + /// '{' (mapLiteralEntry (',' mapLiteralEntry)* ','?)? '}'.
|
| + ///
|
| + /// 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) {
|
| + assert(optional('{', token));
|
| + Token beginToken = token;
|
| + int count = 0;
|
| + bool old = mayParseFunctionExpressions;
|
| + mayParseFunctionExpressions = true;
|
| + do {
|
| + if (optional('}', token.next)) {
|
| + token = token.next;
|
| + break;
|
| + }
|
| + token = parseMapLiteralEntry(token.next);
|
| + ++count;
|
| + } while (optional(',', token));
|
| + mayParseFunctionExpressions = old;
|
| + listener.handleLiteralMap(count, beginToken, constKeyword, token);
|
| + return expect('}', token);
|
| + }
|
| +
|
| + /// formalParameterList functionBody.
|
| + ///
|
| + /// 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) {
|
| + assert(optional('(',token));
|
| + 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.
|
| + }
|
| + listener.unexpected(token);
|
| + return null;
|
| + }
|
| +
|
| + /// (typeArguments (
|
| + /// '[' (expressionList ','?)? ']' |
|
| + /// '{' (mapLiteralEntry (',' mapLiteralEntry)* ','?)? '}')) |
|
| + /// typeParameters formalParameterList functionBody.
|
| + ///
|
| + /// 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 +2385,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 +2427,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);
|
|
|