Remove parser reliance on "<".endGroup/endToken
This replaces calls to lt.endGroup when parsing type arg/param
with calls to computeTypeParamOrArg. This is a step towards
removing lt.endGroup everywhere and making type arg/param
parsing more resiliant and streamlined.
Change-Id: I5b3374769367f601c8910afa18116a2edd3f80c0
Reviewed-on: https://dart-review.googlesource.com/70000
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Dan Rubel <danrubel@google.com>
diff --git a/pkg/front_end/lib/src/fasta/parser/parser.dart b/pkg/front_end/lib/src/fasta/parser/parser.dart
index 9ea2973..3f2075a 100644
--- a/pkg/front_end/lib/src/fasta/parser/parser.dart
+++ b/pkg/front_end/lib/src/fasta/parser/parser.dart
@@ -1320,9 +1320,11 @@
next = token.next;
}
Token beforeInlineFunctionType;
+ TypeParamOrArgInfo typeParam = noTypeParamOrArg;
if (optional("<", next)) {
- Token closer = next.endGroup;
- if (closer != null) {
+ typeParam = computeTypeParamOrArg(token);
+ if (typeParam != noTypeParamOrArg) {
+ Token closer = typeParam.skip(token);
if (optional("(", closer.next)) {
if (varFinalOrConst != null) {
reportRecoverableError(
@@ -1350,8 +1352,8 @@
Token endInlineFunctionType;
if (beforeInlineFunctionType != null) {
- endInlineFunctionType = computeTypeParamOrArg(beforeInlineFunctionType)
- .parseVariables(beforeInlineFunctionType, this);
+ endInlineFunctionType =
+ typeParam.parseVariables(beforeInlineFunctionType, this);
listener.beginFunctionTypedFormalParameter(beforeInlineFunctionType.next);
token = typeInfo.parseType(beforeType, this);
endInlineFunctionType = parseFormalParametersRequiredOpt(
@@ -2152,17 +2154,15 @@
}
Token parseMethodTypeVar(Token name) {
+ if (!optional('<', name.next)) {
+ return noTypeParamOrArg.parseVariables(name, this);
+ }
TypeParamOrArgInfo typeVar = computeTypeParamOrArg(name, true);
- Token token;
- if (typeVar == noTypeParamOrArg || name.next.endGroup != null) {
- token = typeVar.parseVariables(name, this);
- } else {
+ Token token = typeVar.parseVariables(name, this);
+ if (optional('=', token.next)) {
// Recovery
- token = typeVar.parseVariables(name, this);
- if (optional('=', token.next)) {
- token = token.next;
- reportRecoverableErrorWithToken(token, fasta.templateUnexpectedToken);
- }
+ token = token.next;
+ reportRecoverableErrorWithToken(token, fasta.templateUnexpectedToken);
}
return token;
}
@@ -2642,9 +2642,10 @@
// Fall through to continue parsing `factory` as an identifier.
} else if (identical(value, 'operator')) {
Token next2 = next.next;
+ TypeParamOrArgInfo typeParam = computeTypeParamOrArg(next);
// `operator` can be used as an identifier as in
// `int operator<T>()` or `int operator = 2`
- if (next2.isUserDefinableOperator && next2.endGroup == null) {
+ if (next2.isUserDefinableOperator && typeParam == noTypeParamOrArg) {
token = parseMethod(
beforeStart,
externalToken,
@@ -2916,7 +2917,7 @@
assert(optional('operator', token));
Token next = token.next;
if (next.isUserDefinableOperator) {
- if (next.endGroup != null) {
+ if (computeTypeParamOrArg(token) != noTypeParamOrArg) {
// `operator` is being used as an identifier.
// For example: `int operator<T>(foo) => 0;`
listener.handleIdentifier(token, IdentifierContext.methodDeclaration);
@@ -2957,11 +2958,13 @@
}
Token parseFunctionLiteral(
- final Token start, TypeInfo typeInfo, IdentifierContext context) {
- Token beforeName = typeInfo.skipType(start);
- Token name = beforeName.next;
- assert(name.isIdentifier);
- Token formals = computeTypeParamOrArg(name).parseVariables(name, this);
+ Token start,
+ Token beforeName,
+ Token name,
+ TypeInfo typeInfo,
+ TypeParamOrArgInfo typeParam,
+ IdentifierContext context) {
+ Token formals = typeParam.parseVariables(name, this);
listener.beginNamedFunctionExpression(start.next);
typeInfo.parseType(start, this);
return parseNamedFunctionRest(beforeName, start.next, formals, true);
@@ -3022,13 +3025,14 @@
return token;
}
- Token parseConstructorReference(Token token) {
+ Token parseConstructorReference(Token token, [TypeParamOrArgInfo typeArg]) {
Token start =
ensureIdentifier(token, IdentifierContext.constructorReference);
listener.beginConstructorReference(start);
token = parseQualifiedRestOpt(
start, IdentifierContext.constructorReferenceContinuation);
- token = computeTypeParamOrArg(token).parseArguments(token, this);
+ typeArg ??= computeTypeParamOrArg(token);
+ token = typeArg.parseArguments(token, this);
Token period = null;
if (optional('.', token.next)) {
period = token.next;
@@ -3703,11 +3707,12 @@
if (identifier.isIdentifier) {
// Looking at `identifier ('.' identifier)?`.
if (optional("<", identifier.next)) {
- BeginToken typeArguments = identifier.next;
- Token endTypeArguments = typeArguments.endGroup;
- if (endTypeArguments != null &&
- optional(".", endTypeArguments.next)) {
- return parseImplicitCreationExpression(token);
+ TypeParamOrArgInfo typeArg = computeTypeParamOrArg(identifier);
+ if (typeArg != noTypeParamOrArg) {
+ Token endTypeArguments = typeArg.skip(identifier);
+ if (optional(".", endTypeArguments.next)) {
+ return parseImplicitCreationExpression(token, typeArg);
+ }
}
}
}
@@ -4126,10 +4131,23 @@
return parseSend(token, context);
}
TypeInfo typeInfo = computeType(token, false);
- if (!looksLikeFunctionDeclaration(typeInfo.skipType(token).next)) {
- return parseSend(token, context);
+ Token beforeName = typeInfo.skipType(token);
+ Token name = beforeName.next;
+ if (name.isIdentifier) {
+ TypeParamOrArgInfo typeParam = computeTypeParamOrArg(name);
+ Token next = name;
+ if (typeParam != noTypeParamOrArg) {
+ next = typeParam.skip(next);
+ }
+ next = next.next;
+ if (optional('(', next)) {
+ if (looksLikeFunctionBody(next.endGroup.next)) {
+ return parseFunctionLiteral(
+ token, beforeName, name, typeInfo, typeParam, context);
+ }
+ }
}
- return parseFunctionLiteral(token, typeInfo, context);
+ return parseSend(token, context);
}
Token parseRequiredArguments(Token token) {
@@ -4158,10 +4176,11 @@
return token;
}
- Token parseImplicitCreationExpression(Token token) {
+ Token parseImplicitCreationExpression(
+ Token token, TypeParamOrArgInfo typeArg) {
Token begin = token;
listener.beginImplicitCreationExpression(token);
- token = parseConstructorReference(token);
+ token = parseConstructorReference(token, typeArg);
token = parseRequiredArguments(token);
listener.endImplicitCreationExpression(begin);
return token;
@@ -4519,14 +4538,14 @@
/// without a return type.
bool looksLikeLocalFunction(Token token) {
if (token.isIdentifier) {
- token = token.next;
- if (optional('<', token)) {
- Token closeBrace = token.endGroup;
- if (closeBrace == null) {
+ if (optional('<', token.next)) {
+ TypeParamOrArgInfo typeParam = computeTypeParamOrArg(token);
+ if (typeParam == noTypeParamOrArg) {
return false;
}
- token = closeBrace.next;
+ token = typeParam.skip(token);
}
+ token = token.next;
if (optional('(', token)) {
token = token.endGroup.next;
return optional('{', token) ||
@@ -4549,24 +4568,6 @@
optional('sync', token);
}
- /// Returns true if [token] could be the start of a function declaration
- /// without a return type.
- bool looksLikeFunctionDeclaration(Token token) {
- if (!token.isIdentifier) {
- return false;
- }
- token = token.next;
- if (optional('<', token)) {
- Token closeBrace = token.endGroup;
- if (closeBrace == null) return false;
- token = closeBrace.next;
- }
- if (optional('(', token)) {
- return looksLikeFunctionBody(token.endGroup.next);
- }
- return false;
- }
-
Token parseExpressionStatementOrConstDeclaration(final Token start) {
Token constToken = start.next;
assert(optional('const', constToken));
@@ -4651,22 +4652,24 @@
Token token = typeInfo.skipType(beforeType);
Token next = token.next;
- if (!onlyParseVariableDeclarationStart && looksLikeLocalFunction(next)) {
- // Parse a local function declaration.
- if (varFinalOrConst != null) {
- reportRecoverableErrorWithToken(
- varFinalOrConst, fasta.templateExtraneousModifier);
+ if (!onlyParseVariableDeclarationStart) {
+ if (looksLikeLocalFunction(next)) {
+ // Parse a local function declaration.
+ if (varFinalOrConst != null) {
+ reportRecoverableErrorWithToken(
+ varFinalOrConst, fasta.templateExtraneousModifier);
+ }
+ if (!optional('@', start.next)) {
+ listener.beginMetadataStar(start.next);
+ listener.endMetadataStar(0);
+ }
+ Token beforeFormals =
+ computeTypeParamOrArg(next).parseVariables(next, this);
+ listener.beginLocalFunctionDeclaration(start.next);
+ token = typeInfo.parseType(beforeType, this);
+ next = token.next;
+ return parseNamedFunctionRest(token, start.next, beforeFormals, false);
}
- if (!optional('@', start.next)) {
- listener.beginMetadataStar(start.next);
- listener.endMetadataStar(0);
- }
- Token beforeFormals =
- computeTypeParamOrArg(next).parseVariables(next, this);
- listener.beginLocalFunctionDeclaration(start.next);
- token = typeInfo.parseType(beforeType, this);
- next = token.next;
- return parseNamedFunctionRest(token, start.next, beforeFormals, false);
}
if (token == start) {
diff --git a/pkg/front_end/testcases/regress/issue_31155.dart.direct.expect b/pkg/front_end/testcases/regress/issue_31155.dart.direct.expect
index 0f54478..d785e40 100644
--- a/pkg/front_end/testcases/regress/issue_31155.dart.direct.expect
+++ b/pkg/front_end/testcases/regress/issue_31155.dart.direct.expect
@@ -21,19 +21,6 @@
// pkg/front_end/testcases/regress/issue_31155.dart:11:23: Error: Expected a class member, but got ';'.
// var f = Map<A, B> {};
// ^
-//
-// pkg/front_end/testcases/regress/issue_31155.dart:11:11: Error: A function expression can't have a name.
-// var f = Map<A, B> {};
-// ^^^
-//
-// pkg/front_end/testcases/regress/issue_31155.dart:11:14: Error: A function declaration needs an explicit list of parameters.
-// Try adding a parameter list to the function declaration.
-// var f = Map<A, B> {};
-// ^
-//
-// pkg/front_end/testcases/regress/issue_31155.dart:11:14: Error: Expected a function body, but got '<'.
-// var f = Map<A, B> {};
-// ^
library;
import self as self;
diff --git a/pkg/front_end/testcases/regress/issue_31155.dart.direct.transformed.expect b/pkg/front_end/testcases/regress/issue_31155.dart.direct.transformed.expect
index 0f54478..d785e40 100644
--- a/pkg/front_end/testcases/regress/issue_31155.dart.direct.transformed.expect
+++ b/pkg/front_end/testcases/regress/issue_31155.dart.direct.transformed.expect
@@ -21,19 +21,6 @@
// pkg/front_end/testcases/regress/issue_31155.dart:11:23: Error: Expected a class member, but got ';'.
// var f = Map<A, B> {};
// ^
-//
-// pkg/front_end/testcases/regress/issue_31155.dart:11:11: Error: A function expression can't have a name.
-// var f = Map<A, B> {};
-// ^^^
-//
-// pkg/front_end/testcases/regress/issue_31155.dart:11:14: Error: A function declaration needs an explicit list of parameters.
-// Try adding a parameter list to the function declaration.
-// var f = Map<A, B> {};
-// ^
-//
-// pkg/front_end/testcases/regress/issue_31155.dart:11:14: Error: Expected a function body, but got '<'.
-// var f = Map<A, B> {};
-// ^
library;
import self as self;
diff --git a/pkg/front_end/testcases/regress/issue_31155.dart.strong.expect b/pkg/front_end/testcases/regress/issue_31155.dart.strong.expect
index f805c54..3b1594e 100644
--- a/pkg/front_end/testcases/regress/issue_31155.dart.strong.expect
+++ b/pkg/front_end/testcases/regress/issue_31155.dart.strong.expect
@@ -21,19 +21,6 @@
// pkg/front_end/testcases/regress/issue_31155.dart:11:23: Error: Expected a class member, but got ';'.
// var f = Map<A, B> {};
// ^
-//
-// pkg/front_end/testcases/regress/issue_31155.dart:11:11: Error: A function expression can't have a name.
-// var f = Map<A, B> {};
-// ^^^
-//
-// pkg/front_end/testcases/regress/issue_31155.dart:11:14: Error: A function declaration needs an explicit list of parameters.
-// Try adding a parameter list to the function declaration.
-// var f = Map<A, B> {};
-// ^
-//
-// pkg/front_end/testcases/regress/issue_31155.dart:11:14: Error: Expected a function body, but got '<'.
-// var f = Map<A, B> {};
-// ^
library;
import self as self;
diff --git a/pkg/front_end/testcases/regress/issue_31155.dart.strong.transformed.expect b/pkg/front_end/testcases/regress/issue_31155.dart.strong.transformed.expect
index e7de89b..868d241 100644
--- a/pkg/front_end/testcases/regress/issue_31155.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/regress/issue_31155.dart.strong.transformed.expect
@@ -21,19 +21,6 @@
// pkg/front_end/testcases/regress/issue_31155.dart:11:23: Error: Expected a class member, but got ';'.
// var f = Map<A, B> {};
// ^
-//
-// pkg/front_end/testcases/regress/issue_31155.dart:11:11: Error: A function expression can't have a name.
-// var f = Map<A, B> {};
-// ^^^
-//
-// pkg/front_end/testcases/regress/issue_31155.dart:11:14: Error: A function declaration needs an explicit list of parameters.
-// Try adding a parameter list to the function declaration.
-// var f = Map<A, B> {};
-// ^
-//
-// pkg/front_end/testcases/regress/issue_31155.dart:11:14: Error: Expected a function body, but got '<'.
-// var f = Map<A, B> {};
-// ^
library;
import self as self;