Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(199)

Unified Diff: pkg/front_end/lib/src/fasta/parser/parser.dart

Issue 2876813002: Implement generalized function types. (Closed)
Patch Set: Address comments. Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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 c6f7697bce1a211fa8903506944fb1d8da1ae81d..dece11f282f0355f92faab5cf8712394d4a7dcfd 100644
--- a/pkg/front_end/lib/src/fasta/parser/parser.dart
+++ b/pkg/front_end/lib/src/fasta/parser/parser.dart
@@ -30,9 +30,7 @@ import '../fasta_codes.dart'
codeExpectedIdentifier,
codeExpectedOpenParens,
codeExpectedString,
- codeExpectedType,
codeExtraneousModifier,
- codeExtraneousModifierReplace,
codeFactoryNotSync,
codeGeneratorReturnsValue,
codeInvalidAwaitFor,
@@ -46,6 +44,8 @@ import '../fasta_codes.dart'
codeRequiredParameterWithDefault,
codeSetterNotSync,
codeStackOverflow,
+ codeTypeAfterVar,
+ codeTypeRequired,
codeUnexpectedToken,
codeUnmatchedToken,
codeUnspecified,
@@ -120,6 +120,44 @@ class FormalParameterType {
static final NAMED = const FormalParameterType('named');
}
+enum MemberKind {
+ /// A catch block, not a real member.
+ Catch,
+
+ /// A factory
+ Factory,
+
+ /// Old-style typedef.
+ FunctionTypeAlias,
+
+ /// Old-style function-typed parameter, not a real member.
+ FunctionTypedParameter,
+
+ /// A generalized function type, not a real member.
+ GeneralizedFunctionType,
+
+ /// A local function.
+ Local,
+
+ /// A non-static method in a class (including constructors).
+ NonStaticMethod,
+
+ /// A static method in a class.
+ StaticMethod,
+
+ /// A top-level method.
+ TopLevelMethod,
+
+ /// An instance field in a class.
+ NonStaticField,
+
+ /// A static field in a class.
+ StaticField,
+
+ /// A top-level field.
+ TopLevelField,
+}
+
/// An event generating parser of Dart programs. This parser expects all tokens
/// in a linked list (aka a token stream).
///
@@ -297,7 +335,8 @@ class Parser {
return parseClassOrNamedMixinApplication(token);
} else if (identical(value, 'enum')) {
return parseEnum(token);
- } else if (identical(value, 'typedef')) {
+ } else if (identical(value, 'typedef') &&
+ (token.next.isIdentifier || optional("void", token.next))) {
return parseTypedef(token);
} else if (identical(value, 'library')) {
return parseLibraryName(token);
@@ -561,7 +600,7 @@ class Parser {
token = parseReturnTypeOpt(token.next);
token = parseIdentifier(token, IdentifierContext.typedefDeclaration);
token = parseTypeVariablesOpt(token);
- token = parseFormalParameters(token);
+ token = parseFormalParameters(token, MemberKind.FunctionTypeAlias);
}
listener.endFunctionTypeAlias(typedefKeyword, equals, token);
return expect(';', token);
@@ -590,16 +629,16 @@ class Parser {
}
}
- Token parseFormalParametersOpt(Token token) {
+ Token parseFormalParametersOpt(Token token, MemberKind kind) {
if (optional('(', token)) {
- return parseFormalParameters(token);
+ return parseFormalParameters(token, kind);
} else {
- listener.handleNoFormalParameters(token);
+ listener.handleNoFormalParameters(token, kind);
return token;
}
}
- Token skipFormalParameters(Token token) {
+ Token skipFormalParameters(Token token, MemberKind kind) {
// TODO(ahe): Shouldn't this be `beginFormalParameters`?
listener.beginOptionalFormalParameters(token);
if (!optional('(', token)) {
@@ -613,17 +652,17 @@ class Parser {
}
BeginGroupToken beginGroupToken = token;
Token endToken = beginGroupToken.endGroup;
- listener.endFormalParameters(0, token, endToken);
+ listener.endFormalParameters(0, token, endToken, kind);
return endToken.next;
}
/// Parses the formal parameter list of a function.
///
- /// If [inFunctionType] is true, then the names may be omitted (except for
- /// named arguments). If it is false, then the types may be omitted.
- Token parseFormalParameters(Token token, {bool inFunctionType: false}) {
+ /// If `kind == MemberKind.GeneralizedFunctionType`, then names may be
+ /// omitted (except for named arguments). Otherwise, types may be omitted.
+ Token parseFormalParameters(Token token, MemberKind kind) {
Token begin = token;
- listener.beginFormalParameters(begin);
+ listener.beginFormalParameters(begin, kind);
expect('(', token);
int parameterCount = 0;
do {
@@ -634,12 +673,10 @@ class Parser {
++parameterCount;
String value = token.stringValue;
if (identical(value, '[')) {
- token = parseOptionalFormalParameters(token, false,
- inFunctionType: inFunctionType);
+ token = parseOptionalFormalParameters(token, false, kind);
break;
} else if (identical(value, '{')) {
- token = parseOptionalFormalParameters(token, true,
- inFunctionType: inFunctionType);
+ token = parseOptionalFormalParameters(token, true, kind);
break;
} else if (identical(value, '[]')) {
--parameterCount;
@@ -647,47 +684,31 @@ class Parser {
token = token.next;
break;
}
- token = parseFormalParameter(token, FormalParameterType.REQUIRED,
- inFunctionType: inFunctionType);
+ token = parseFormalParameter(token, FormalParameterType.REQUIRED, kind);
} while (optional(',', token));
- listener.endFormalParameters(parameterCount, begin, token);
+ listener.endFormalParameters(parameterCount, begin, token, kind);
return expect(')', token);
}
- Token parseFormalParameter(Token token, FormalParameterType kind,
- {bool inFunctionType: false}) {
+ Token parseFormalParameter(
+ Token token, FormalParameterType parameterKind, MemberKind memberKind) {
token = parseMetadataStar(token, forParameter: true);
- listener.beginFormalParameter(token);
-
- // Skip over `covariant` token, if the next token is an identifier or
- // modifier.
- // This enables the case where `covariant` is the name of the parameter:
- // void foo(covariant);
- Token covariantKeyword;
- if (identical(token.stringValue, 'covariant') &&
- (token.next.isIdentifier || isModifier(token.next))) {
- covariantKeyword = token;
- token = token.next;
- }
- token = parseModifiers(token);
- bool isNamedParameter = kind == FormalParameterType.NAMED;
+ listener.beginFormalParameter(token, memberKind);
+
+ bool inFunctionType = memberKind == MemberKind.GeneralizedFunctionType;
+ token = parseModifiers(token, memberKind, parameterKind: parameterKind);
+ bool isNamedParameter = parameterKind == FormalParameterType.NAMED;
Token thisKeyword = null;
Token nameToken;
- if (inFunctionType && isNamedParameter) {
- token = parseType(token);
- token =
- parseIdentifier(token, IdentifierContext.formalParameterDeclaration);
- } else if (inFunctionType) {
- token = parseType(token);
- if (token.isIdentifier) {
+ if (inFunctionType) {
+ if (isNamedParameter || token.isIdentifier) {
token = parseIdentifier(
token, IdentifierContext.formalParameterDeclaration);
} else {
listener.handleNoName(token);
}
} else {
- token = parseReturnTypeOpt(token);
if (optional('this', token)) {
thisKeyword = token;
token = expect('.', token.next);
@@ -705,13 +726,12 @@ class Parser {
Token inlineFunctionTypeStart = token;
listener.beginFunctionTypedFormalParameter(token);
listener.handleNoTypeVariables(token);
- token = parseFormalParameters(token);
- listener.endFunctionTypedFormalParameter(
- covariantKeyword, thisKeyword, kind);
+ token = parseFormalParameters(token, MemberKind.FunctionTypedParameter);
+ listener.endFunctionTypedFormalParameter(thisKeyword, parameterKind);
// Generalized function types don't allow inline function types.
// The following isn't allowed:
// int Function(int bar(String x)).
- if (inFunctionType) {
+ if (memberKind == MemberKind.GeneralizedFunctionType) {
reportRecoverableErrorCode(
inlineFunctionTypeStart, codeInvalidInlineFunctionType);
}
@@ -719,13 +739,12 @@ class Parser {
Token inlineFunctionTypeStart = token;
listener.beginFunctionTypedFormalParameter(token);
token = parseTypeVariablesOpt(token);
- token = parseFormalParameters(token);
- listener.endFunctionTypedFormalParameter(
- covariantKeyword, thisKeyword, kind);
+ token = parseFormalParameters(token, MemberKind.FunctionTypedParameter);
+ listener.endFunctionTypedFormalParameter(thisKeyword, parameterKind);
// Generalized function types don't allow inline function types.
// The following isn't allowed:
// int Function(int bar(String x)).
- if (inFunctionType) {
+ if (memberKind == MemberKind.GeneralizedFunctionType) {
reportRecoverableErrorCode(
inlineFunctionTypeStart, codeInvalidInlineFunctionType);
}
@@ -736,20 +755,21 @@ class Parser {
Token equal = token;
token = parseExpression(token.next);
listener.handleValuedFormalParameter(equal, token);
- if (kind.isRequired) {
+ if (parameterKind.isRequired) {
reportRecoverableErrorCode(equal, codeRequiredParameterWithDefault);
- } else if (kind.isPositional && identical(':', value)) {
+ } else if (parameterKind.isPositional && identical(':', value)) {
reportRecoverableErrorCode(equal, codePositionalParameterWithEquals);
}
} else {
listener.handleFormalParameterWithoutValue(token);
}
- listener.endFormalParameter(covariantKeyword, thisKeyword, nameToken, kind);
+ listener.endFormalParameter(
+ thisKeyword, nameToken, parameterKind, memberKind);
return token;
}
- Token parseOptionalFormalParameters(Token token, bool isNamed,
- {bool inFunctionType: false}) {
+ Token parseOptionalFormalParameters(
+ Token token, bool isNamed, MemberKind kind) {
Token begin = token;
listener.beginOptionalFormalParameters(begin);
assert((isNamed && optional('{', token)) || optional('[', token));
@@ -763,7 +783,7 @@ class Parser {
}
var type =
isNamed ? FormalParameterType.NAMED : FormalParameterType.POSITIONAL;
- token = parseFormalParameter(token, type, inFunctionType: inFunctionType);
+ token = parseFormalParameter(token, type, kind);
++parameterCount;
} while (optional(',', token));
if (parameterCount == 0) {
@@ -796,9 +816,9 @@ class Parser {
}
bool isValidTypeReference(Token token) {
- final kind = token.kind;
- if (identical(kind, IDENTIFIER_TOKEN)) return true;
- if (identical(kind, KEYWORD_TOKEN)) {
+ int kind = token.kind;
+ if (IDENTIFIER_TOKEN == kind) return true;
+ if (KEYWORD_TOKEN == kind) {
String value = token.type.lexeme;
return token.type.isPseudo ||
(identical(value, 'dynamic')) ||
@@ -1033,9 +1053,13 @@ class Parser {
Token parseIdentifier(Token token, IdentifierContext context) {
if (!token.isIdentifier) {
- token =
- reportUnrecoverableErrorCodeWithToken(token, codeExpectedIdentifier)
- .next;
+ if (optional("void", token)) {
+ reportRecoverableErrorCode(token, codeInvalidVoid);
+ } else {
+ token =
+ reportUnrecoverableErrorCodeWithToken(token, codeExpectedIdentifier)
+ .next;
+ }
} else if (token.type.isBuiltIn && !context.isBuiltInIdentifierAllowed) {
if (context.inDeclaration) {
reportRecoverableErrorCodeWithToken(
@@ -1117,20 +1141,18 @@ class Parser {
// Push the non-existing return type first. The loop below will
// generate the full type.
listener.handleNoType(token);
- } else if (identical(token.stringValue, 'void') &&
+ } else if (optional("void", token) &&
isGeneralizedFunctionType(token.next)) {
listener.handleVoidKeyword(token);
token = token.next;
} else {
- if (isValidTypeReference(token)) {
- token = parseIdentifier(token, IdentifierContext.typeReference);
- token = parseQualifiedRestOpt(
- token, IdentifierContext.typeReferenceContinuation);
- } else {
- token =
- reportUnrecoverableErrorCodeWithToken(token, codeExpectedType).next;
- listener.handleInvalidTypeReference(token);
+ IdentifierContext context = IdentifierContext.typeReference;
+ if (token.isIdentifier && optional(".", token.next)) {
+ context = IdentifierContext.prefixedTypeReference;
}
+ token = parseIdentifier(token, context);
+ token = parseQualifiedRestOpt(
+ token, IdentifierContext.typeReferenceContinuation);
token = parseTypeArgumentsOpt(token);
listener.handleType(begin, token);
}
@@ -1160,7 +1182,7 @@ class Parser {
Token functionToken = token;
token = token.next;
token = parseTypeVariablesOpt(token);
- token = parseFormalParameters(token, inFunctionType: true);
+ token = parseFormalParameters(token, MemberKind.GeneralizedFunctionType);
listener.handleFunctionType(functionToken, token);
return token;
}
@@ -1279,141 +1301,21 @@ class Parser {
: parseTopLevelMethod(start, modifiers, type, getOrSet, name);
}
- bool isVarFinalOrConst(Token token) {
- String value = token.stringValue;
- return identical('var', value) ||
- identical('final', value) ||
- identical('const', value);
- }
-
- Token expectVarFinalOrConst(
- Link<Token> modifiers, bool hasType, bool allowStatic) {
- int modifierCount = 0;
- Token staticModifier;
- if (allowStatic &&
- !modifiers.isEmpty &&
- optional('static', modifiers.head)) {
- staticModifier = modifiers.head;
- modifierCount++;
- parseModifier(staticModifier);
- modifiers = modifiers.tail;
- }
- if (modifiers.isEmpty) {
- listener.handleModifiers(modifierCount);
- return null;
- }
- if (modifiers.tail.isEmpty) {
- Token modifier = modifiers.head;
- if (isVarFinalOrConst(modifier)) {
- modifierCount++;
- parseModifier(modifier);
- listener.handleModifiers(modifierCount);
- // TODO(ahe): The caller checks for "var Type name", perhaps we should
- // check here instead.
- return modifier;
- }
- }
-
- // Slow case to report errors.
- List<Token> modifierList = modifiers.toList();
- Token varFinalOrConst =
- modifierList.firstWhere(isVarFinalOrConst, orElse: () => null);
- if (allowStatic && staticModifier == null) {
- staticModifier = modifierList.firstWhere(
- (modifier) => optional('static', modifier),
- orElse: () => null);
- if (staticModifier != null) {
- modifierCount++;
- parseModifier(staticModifier);
- modifierList.remove(staticModifier);
- }
- }
- bool hasTypeOrModifier = hasType;
- if (varFinalOrConst != null) {
- parseModifier(varFinalOrConst);
- modifierCount++;
- hasTypeOrModifier = true;
- modifierList.remove(varFinalOrConst);
- }
- listener.handleModifiers(modifierCount);
- for (Token modifier in modifierList) {
- reportRecoverableErrorCodeWithToken(
- modifier,
- hasTypeOrModifier
- ? codeExtraneousModifier
- : codeExtraneousModifierReplace);
- }
- return null;
- }
-
- /// Removes the optional `covariant` token from the modifiers, if there
- /// is no `static` in the list, and `covariant` is the first modifier.
- Link<Token> removeOptCovariantTokenIfNotStatic(Link<Token> modifiers) {
- if (modifiers.isEmpty ||
- !identical(modifiers.first.stringValue, 'covariant')) {
- return modifiers;
- }
- for (Token modifier in modifiers.tail) {
- if (identical(modifier.stringValue, 'static')) {
- return modifiers;
- }
- }
- return modifiers.tail;
- }
-
Token parseFields(Token start, Link<Token> modifiers, Token type,
Token getOrSet, Token name, bool isTopLevel) {
- bool hasType = type != null;
-
- Token covariantKeyword;
- if (getOrSet == null && !isTopLevel) {
- // TODO(ahe): replace the method removeOptCovariantTokenIfNotStatic with
- // a better mechanism.
- Link<Token> newModifiers = removeOptCovariantTokenIfNotStatic(modifiers);
- if (!identical(newModifiers, modifiers)) {
- covariantKeyword = modifiers.first;
- modifiers = newModifiers;
- }
- }
-
- Token varFinalOrConst =
- expectVarFinalOrConst(modifiers, hasType, !isTopLevel);
- bool isVar = false;
- bool hasModifier = false;
- if (varFinalOrConst != null) {
- hasModifier = true;
- isVar = optional('var', varFinalOrConst);
- }
+ Token token = parseModifiers(start,
+ isTopLevel ? MemberKind.TopLevelField : MemberKind.NonStaticField,
+ isVariable: true);
- if (getOrSet != null) {
- reportRecoverableErrorCodeWithToken(
- getOrSet,
- hasModifier || hasType
- ? codeExtraneousModifier
- : codeExtraneousModifierReplace);
- }
-
- if (!hasType) {
- listener.handleNoType(name);
- } else if (optional('void', type) &&
- !isGeneralizedFunctionType(type.next)) {
- listener.handleNoType(name);
- // TODO(ahe): This error is reported twice, second time is from
- // [parseVariablesDeclarationMaybeSemicolon] via
- // [PartialFieldListElement.parseNode].
- reportRecoverableErrorCode(type, codeInvalidVoid);
- } else {
- parseType(type);
- if (isVar) {
- reportRecoverableErrorCodeWithToken(
- modifiers.head, codeExtraneousModifier);
- }
+ if (token != name) {
+ reportRecoverableErrorCodeWithToken(token, codeExtraneousModifier);
+ token = name;
}
IdentifierContext context = isTopLevel
? IdentifierContext.topLevelVariableDeclaration
: IdentifierContext.fieldDeclaration;
- Token token = parseIdentifier(name, context);
+ token = parseIdentifier(token, context);
int fieldCount = 1;
token = parseFieldInitializerOpt(token);
@@ -1427,7 +1329,7 @@ class Parser {
if (isTopLevel) {
listener.endTopLevelFields(fieldCount, start, semicolon);
} else {
- listener.endFields(fieldCount, covariantKeyword, start, semicolon);
+ listener.endFields(fieldCount, start, semicolon);
}
return token;
}
@@ -1465,7 +1367,7 @@ class Parser {
} else {
listener.handleNoTypeVariables(token);
}
- token = parseFormalParametersOpt(token);
+ token = parseFormalParametersOpt(token, MemberKind.TopLevelMethod);
AsyncModifier savedAsyncModifier = asyncState;
Token asyncToken = token;
token = parseAsyncModifier(token);
@@ -1683,14 +1585,30 @@ class Parser {
return expect(';', token);
}
- bool isModifier(Token token) {
+ bool isModifier(Token token) => modifierOrder(token) < 127;
+
+ /// Provides a partial order on modifiers.
+ ///
+ /// The order is based on the order modifiers must appear in according to the
+ /// grammar. For example, `external` must come before `static`.
+ ///
+ /// In addition, if two modifiers have the same order, they can't both be
+ /// used together, for example, `final` and `var` can't be used together.
+ ///
+ /// If [token] isn't a modifier, 127 is returned.
+ int modifierOrder(Token token) {
final String value = token.stringValue;
- return (identical('final', value)) ||
- (identical('var', value)) ||
- (identical('const', value)) ||
- (identical('abstract', value)) ||
- (identical('static', value)) ||
- (identical('external', value));
+ if (identical('external', value)) return 0;
+ if (identical('static', value) || identical('covariant', value)) {
+ return 1;
+ }
+ if (identical('final', value) ||
+ identical('var', value) ||
+ identical('const', value)) {
+ return 2;
+ }
+ if (identical('abstract', value)) return 3;
+ return 127;
}
Token parseModifier(Token token) {
@@ -1699,35 +1617,124 @@ class Parser {
return token.next;
}
- void parseModifierList(Link<Token> tokens) {
+ /// This method is used in most locations where modifiers can occur. However,
+ /// it isn't used when parsing a class or when parsing the modifiers of a
+ /// member function (non-local), but is used when parsing their formal
+ /// parameters.
+ ///
+ /// When parsing the formal parameters of any function, [parameterKind] is
+ /// non-null.
+ Token parseModifiers(Token token, MemberKind memberKind,
+ {FormalParameterType parameterKind, bool isVariable: false}) {
+ bool returnTypeAllowed =
+ !isVariable && memberKind != MemberKind.GeneralizedFunctionType;
+ bool typeRequired =
+ isVariable || memberKind == MemberKind.GeneralizedFunctionType;
int count = 0;
- for (; !tokens.isEmpty; tokens = tokens.tail) {
- Token token = tokens.head;
- if (isModifier(token)) {
- parseModifier(token);
+
+ int currentOrder = -1;
+ bool hasVar = false;
+ while (token.kind == KEYWORD_TOKEN) {
+ if (token.type.isPseudo) {
+ // A pseudo keyword is never a modifier.
+ break;
+ }
+ if (token.type.isBuiltIn) {
+ // A built-in identifier can only be a modifier as long as it is
+ // followed by another modifier or an identifier. Otherwise, it is the
+ // identifier.
+ if (token.next.kind != KEYWORD_TOKEN && !token.next.isIdentifier) {
+ break;
+ }
+ }
+ int order = modifierOrder(token);
+ if (order < 3) {
+ // `abstract` isn't parsed with this method.
+ if (order > currentOrder) {
+ currentOrder = order;
+ if (optional("var", token)) {
+ if (!isVariable && parameterKind == null) {
+ reportRecoverableErrorCodeWithToken(
+ token, codeExtraneousModifier);
+ }
+ hasVar = true;
+ typeRequired = false;
+ } else if (optional("final", token)) {
+ if (!isVariable && parameterKind == null) {
+ reportRecoverableErrorCodeWithToken(
+ token, codeExtraneousModifier);
+ }
+ typeRequired = false;
+ } else if (optional("const", token)) {
+ if (!isVariable) {
+ reportRecoverableErrorCodeWithToken(
+ token, codeExtraneousModifier);
+ }
+ typeRequired = false;
+ } else if (optional("static", token)) {
+ if (memberKind == MemberKind.NonStaticMethod) {
+ memberKind = MemberKind.StaticMethod;
+ } else if (memberKind == MemberKind.NonStaticField) {
+ memberKind = MemberKind.StaticField;
+ } else {
+ reportRecoverableErrorCodeWithToken(
+ token, codeExtraneousModifier);
+ token = token.next;
+ continue;
+ }
+ } else if (optional("covariant", token)) {
+ switch (memberKind) {
+ case MemberKind.StaticField:
+ case MemberKind.StaticMethod:
+ case MemberKind.TopLevelField:
+ case MemberKind.TopLevelMethod:
+ reportRecoverableErrorCodeWithToken(
+ token, codeExtraneousModifier);
+ token = token.next;
+ continue;
+
+ default:
+ break;
+ }
+ } else if (optional("external", token)) {
+ switch (memberKind) {
+ case MemberKind.Factory:
+ case MemberKind.NonStaticMethod:
+ case MemberKind.StaticMethod:
+ case MemberKind.TopLevelMethod:
+ break;
+
+ default:
+ reportRecoverableErrorCodeWithToken(
+ token, codeExtraneousModifier);
+ token = token.next;
+ continue;
+ }
+ }
+ token = parseModifier(token);
+ count++;
+ } else {
+ reportRecoverableErrorCodeWithToken(token, codeExtraneousModifier);
+ token = token.next;
+ }
} else {
- reportUnexpectedToken(token);
- // Skip the remaining modifiers.
break;
}
- count++;
}
listener.handleModifiers(count);
- }
- Token parseModifiers(Token token) {
- // TODO(ahe): The calling convention of this method probably needs to
- // change. For example, this is parsed as a local variable declaration:
- // `abstract foo;`. Ideally, this example should be handled as a local
- // variable having the type `abstract` (which should be reported as
- // `codeBuiltInIdentifierAsType` by [parseIdentifier]).
- int count = 0;
- while (identical(token.kind, KEYWORD_TOKEN)) {
- if (!isModifier(token)) break;
- token = parseModifier(token);
- count++;
+ Token beforeType = token;
+ if (returnTypeAllowed) {
+ token = parseReturnTypeOpt(token);
+ } else {
+ token = typeRequired ? parseType(token) : parseTypeOpt(token);
+ }
+ if (typeRequired && beforeType == token) {
+ reportRecoverableErrorCode(token, codeTypeRequired);
+ }
+ if (hasVar && beforeType != token) {
+ reportRecoverableErrorCode(beforeType, codeTypeAfterVar);
}
- listener.handleModifiers(count);
return token;
}
@@ -1950,7 +1957,7 @@ class Parser {
token = reportUnexpectedToken(token).next;
if (identical(token.kind, EOF_TOKEN)) {
// TODO(ahe): This is a hack, see parseTopLevelMember.
- listener.endFields(1, null, start, token);
+ listener.endFields(1, start, token);
listener.endMember();
return token;
}
@@ -1968,41 +1975,59 @@ class Parser {
Token parseMethod(Token start, Link<Token> modifiers, Token type,
Token getOrSet, Token name) {
listener.beginMethod(start, name);
+
Token externalModifier;
Token staticModifier;
- Token constModifier;
- int modifierCount = 0;
- int allowedModifierCount = 1;
- // TODO(johnniwinther): Move error reporting to resolution to give more
- // specific error messages.
- for (Token modifier in modifiers) {
- if (externalModifier == null && optional('external', modifier)) {
- modifierCount++;
- externalModifier = modifier;
- if (modifierCount != allowedModifierCount) {
- reportRecoverableErrorCodeWithToken(modifier, codeExtraneousModifier);
- }
- allowedModifierCount++;
- } else if (staticModifier == null && optional('static', modifier)) {
- modifierCount++;
- staticModifier = modifier;
- if (modifierCount != allowedModifierCount) {
- reportRecoverableErrorCodeWithToken(modifier, codeExtraneousModifier);
+ // TODO(ahe): Consider using [parseModifiers] instead.
+ void parseModifierList(Link<Token> tokens) {
+ int count = 0;
+ int currentOrder = -1;
+ for (; !tokens.isEmpty; tokens = tokens.tail) {
+ Token token = tokens.head;
+ if (optional("abstract", token)) {
+ reportRecoverableErrorCodeWithToken(token, codeExtraneousModifier);
+ continue;
}
- } else if (constModifier == null && optional('const', modifier)) {
- modifierCount++;
- constModifier = modifier;
- if (modifierCount != allowedModifierCount) {
- reportRecoverableErrorCodeWithToken(modifier, codeExtraneousModifier);
+ int order = modifierOrder(token);
+ if (order < 127) {
+ if (order > currentOrder) {
+ currentOrder = order;
+ if (optional("var", token)) {
+ reportRecoverableErrorCodeWithToken(
+ token, codeExtraneousModifier);
+ } else if (optional("const", token)) {
+ if (getOrSet != null) {
+ reportRecoverableErrorCodeWithToken(
+ token, codeExtraneousModifier);
+ continue;
+ }
+ } else if (optional("external", token)) {
+ externalModifier = token;
+ } else if (optional("static", token)) {
+ staticModifier = token;
+ } else if (optional("covariant", token)) {
+ if (staticModifier != null ||
+ getOrSet == null ||
+ optional("get", getOrSet)) {
+ reportRecoverableErrorCodeWithToken(
+ token, codeExtraneousModifier);
+ continue;
+ }
+ }
+ } else {
+ reportRecoverableErrorCodeWithToken(token, codeExtraneousModifier);
+ continue;
+ }
+ } else {
+ reportUnexpectedToken(token);
+ break; // Skip the remaining modifiers.
}
- } else {
- reportRecoverableErrorCodeWithToken(modifier, codeExtraneousModifier);
+ parseModifier(token);
+ count++;
}
+ listener.handleModifiers(count);
}
- if (getOrSet != null && constModifier != null) {
- reportRecoverableErrorCodeWithToken(
- constModifier, codeExtraneousModifier);
- }
+
parseModifierList(modifiers);
if (type == null) {
@@ -2028,7 +2053,11 @@ class Parser {
} else {
listener.handleNoTypeVariables(token);
}
- token = parseFormalParametersOpt(token);
+ token = parseFormalParametersOpt(
+ token,
+ staticModifier != null
+ ? MemberKind.StaticMethod
+ : MemberKind.NonStaticMethod);
token = parseInitializersOpt(token);
AsyncModifier savedAsyncModifier = asyncState;
Token asyncToken = token;
@@ -2064,7 +2093,7 @@ class Parser {
listener.beginFactoryMethod(factoryKeyword);
token = expect('factory', token);
token = parseConstructorReference(token);
- token = parseFormalParameters(token);
+ token = parseFormalParameters(token, MemberKind.Factory);
Token asyncToken = token;
token = parseAsyncModifier(token);
if (!inPlainSync) {
@@ -2091,62 +2120,30 @@ class Parser {
}
}
- Token parseFunction(Token token, Token getOrSet) {
+ Token parseFunction(Token token) {
Token beginToken = token;
listener.beginFunction(token);
- token = parseModifiers(token);
- if (identical(getOrSet, token)) {
- // get <name> => ...
- token = token.next;
- listener.handleNoType(token);
- listener.beginFunctionName(token);
- if (optional('operator', token)) {
- token = parseOperatorName(token);
- } else {
- token =
- parseIdentifier(token, IdentifierContext.localAccessorDeclaration);
- }
- } else if (optional('operator', token)) {
- // operator <op> (...
- listener.handleNoType(token);
- listener.beginFunctionName(token);
- token = parseOperatorName(token);
- } else {
- // <type>? <get>? <name>
- token = parseReturnTypeOpt(token);
- if (identical(getOrSet, token)) {
- token = token.next;
- }
- listener.beginFunctionName(token);
- if (optional('operator', token)) {
- token = parseOperatorName(token);
- } else {
- token =
- parseIdentifier(token, IdentifierContext.localFunctionDeclaration);
- }
- }
+ token = parseModifiers(token, MemberKind.Local);
+ listener.beginFunctionName(token);
+ token = parseIdentifier(token, IdentifierContext.localFunctionDeclaration);
token = parseQualifiedRestOpt(
token, IdentifierContext.localFunctionDeclarationContinuation);
listener.endFunctionName(beginToken, token);
- if (getOrSet == null) {
- token = parseTypeVariablesOpt(token);
- } else {
- listener.handleNoTypeVariables(token);
- }
- token = parseFormalParametersOpt(token);
+ token = parseTypeVariablesOpt(token);
+ token = parseFormalParametersOpt(token, MemberKind.Local);
token = parseInitializersOpt(token);
AsyncModifier savedAsyncModifier = asyncState;
token = parseAsyncModifier(token);
token = parseFunctionBody(token, false, true);
asyncState = savedAsyncModifier;
- listener.endFunction(getOrSet, token);
+ listener.endFunction(null, token);
return token.next;
}
Token parseUnnamedFunction(Token token) {
Token beginToken = token;
listener.beginUnnamedFunction(token);
- token = parseFormalParameters(token);
+ token = parseFormalParameters(token, MemberKind.Local);
AsyncModifier savedAsyncModifier = asyncState;
token = parseAsyncModifier(token);
bool isBlock = optional('{', token);
@@ -2158,7 +2155,7 @@ class Parser {
Token parseFunctionDeclaration(Token token) {
listener.beginFunctionDeclaration(token);
- token = parseFunction(token, null);
+ token = parseFunction(token);
listener.endFunctionDeclaration(token);
return token;
}
@@ -2172,7 +2169,7 @@ class Parser {
token = parseIdentifier(token, IdentifierContext.functionExpressionName);
listener.endFunctionName(beginToken, token);
token = parseTypeVariablesOpt(token);
- token = parseFormalParameters(token);
+ token = parseFormalParameters(token, MemberKind.Local);
listener.handleNoInitializers();
AsyncModifier savedAsyncModifier = asyncState;
token = parseAsyncModifier(token);
@@ -3412,13 +3409,12 @@ class Parser {
// If the next token has a type substitution comment /*=T*/, then
// the current 'var' token should be repealed and replaced.
- if (identical('var', token.stringValue)) {
+ if (optional('var', token)) {
token =
listener.replaceTokenWithGenericCommentTypeAssign(token, token.next);
}
- token = parseModifiers(token);
- token = parseTypeOpt(token);
+ token = parseModifiers(token, MemberKind.Local, isVariable: true);
listener.beginVariablesDeclaration(token);
token = parseOptionallyInitializedIdentifier(token);
while (optional(',', token)) {
@@ -3640,7 +3636,7 @@ class Parser {
if (identical(value, 'catch')) {
catchKeyword = token;
// TODO(ahe): Validate the "parameters".
- token = parseFormalParameters(token.next);
+ token = parseFormalParameters(token.next, MemberKind.Catch);
}
listener.endCatchClause(token);
token = parseBlock(token);
« no previous file with comments | « pkg/front_end/lib/src/fasta/parser/listener.dart ('k') | pkg/front_end/lib/src/fasta/source/diet_listener.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698