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 02bee28ffd2e7a27d90d854c873a7754b8e2dd98..81ced1ac698c110ed1707340a35e180645f9432d 100644 |
--- a/pkg/front_end/lib/src/fasta/parser/parser.dart |
+++ b/pkg/front_end/lib/src/fasta/parser/parser.dart |
@@ -180,6 +180,29 @@ enum Assert { |
Statement, |
} |
+/// Indication of how the parser should continue after (attempting) to parse a |
+/// type. |
+/// |
+/// Depending on the continuation, the parser may not parse a type at all. |
+enum TypeContinuation { |
+ /// Indicates that a type is unconditionally expected. |
+ Required, |
+ |
+ /// Indicates that a type may follow. If the following matches one of these |
+ /// productions, it is parsed as a type: |
+ /// |
+ /// - `'void'` |
+ /// - `'Function' ( '(' | '<' )` |
+ /// - `identifier ('.' identifier)? ('<' ... '>')? identifer` |
+ /// |
+ /// Otherwise, do nothing. |
+ Optional, |
+ |
+ /// Indicates that the keyword `typedef` has just been seen, and the parser |
+ /// should parse the following as a type unless it is followed by `=`. |
+ Typedef, |
+} |
+ |
/// An event generating parser of Dart programs. This parser expects all tokens |
/// in a linked list (aka a token stream). |
/// |
@@ -615,14 +638,15 @@ class Parser { |
Token typedefKeyword = token; |
listener.beginFunctionTypeAlias(token); |
Token equals; |
- if (optional('=', peekAfterNominalType(token.next))) { |
+ Token afterType = parseType(token.next, TypeContinuation.Typedef); |
+ if (afterType == null) { |
token = parseIdentifier(token.next, IdentifierContext.typedefDeclaration); |
token = parseTypeVariablesOpt(token); |
equals = token; |
token = expect('=', token); |
token = parseType(token); |
} else { |
- token = parseType(token.next, isOptional: true); |
+ token = afterType; |
token = parseIdentifier(token, IdentifierContext.typedefDeclaration); |
token = parseTypeVariablesOpt(token); |
token = parseFormalParameters(token, MemberKind.FunctionTypeAlias); |
@@ -968,40 +992,28 @@ class Parser { |
} |
Token parseClassOrNamedMixinApplication(Token token) { |
+ listener.beginClassOrNamedMixinApplication(token); |
Token begin = token; |
- Token abstractKeyword; |
- Token classKeyword = token; |
if (optional('abstract', token)) { |
- abstractKeyword = token; |
- token = token.next; |
- classKeyword = token; |
- } |
- assert(optional('class', classKeyword)); |
- int modifierCount = 0; |
- if (abstractKeyword != null) { |
- parseModifier(abstractKeyword); |
- modifierCount++; |
- } |
- listener.handleModifiers(modifierCount); |
- bool isMixinApplication = optional('=', peekAfterNominalType(token)); |
- Token name = token.next; |
- |
- if (isMixinApplication) { |
- token = parseIdentifier(name, IdentifierContext.namedMixinDeclaration); |
- listener.beginNamedMixinApplication(begin, name); |
+ token = parseModifier(token); |
+ listener.handleModifiers(1); |
} else { |
- token = parseIdentifier(name, IdentifierContext.classDeclaration); |
- listener.beginClassDeclaration(begin, name); |
+ listener.handleModifiers(0); |
} |
- |
+ Token classKeyword = token; |
+ token = expect("class", token); |
+ Token name = token; |
+ token = |
+ parseIdentifier(name, IdentifierContext.classOrNamedMixinDeclaration); |
token = parseTypeVariablesOpt(token); |
- |
if (optional('=', token)) { |
+ listener.beginNamedMixinApplication(begin, name); |
Token equals = token; |
token = token.next; |
return parseNamedMixinApplication( |
token, begin, classKeyword, name, equals); |
} else { |
+ listener.beginClassDeclaration(begin, name); |
return parseClass(token, begin, classKeyword, name); |
} |
} |
@@ -1139,9 +1151,21 @@ class Parser { |
(optional('<', token.next) || optional('(', token.next)); |
} |
- Token parseType(Token token, {bool isOptional: false}) { |
- if (isOptional) { |
- do { |
+ /// Parse a type, if it is appropriate to do so. |
+ /// |
+ /// If this method can parse a type, it will return the next (non-null) token |
+ /// after the type. Otherwise, it returns null. |
+ Token parseType(Token token, |
+ [TypeContinuation continuation = TypeContinuation.Required]) { |
+ switch (continuation) { |
+ case TypeContinuation.Typedef: |
+ if (optional('=', peekAfterNominalType(token))) { |
+ return null; // This isn't a type, it's a new-style typedef. |
+ } |
+ continue optional; |
+ |
+ optional: |
+ case TypeContinuation.Optional: |
if (optional("void", token)) { |
if (isGeneralizedFunctionType(token.next)) { |
// This is a type, parse it. |
@@ -1164,7 +1188,13 @@ class Parser { |
listener.handleNoType(token); |
return token; |
} |
- } while (false); |
+ break; |
+ |
+ case TypeContinuation.Required: |
+ break; |
+ |
+ default: |
+ throw "Internal error: Unhandled continuation '$continuation'."; |
} |
Token begin = token; |
if (isGeneralizedFunctionType(token)) { |
@@ -1399,7 +1429,7 @@ class Parser { |
if (type == null) { |
listener.handleNoType(name); |
} else { |
- parseType(type, isOptional: true); |
+ parseType(type, TypeContinuation.Optional); |
} |
Token token = |
parseIdentifier(name, IdentifierContext.topLevelFunctionDeclaration); |
@@ -1799,7 +1829,11 @@ class Parser { |
listener.handleModifiers(count); |
Token beforeType = token; |
- token = parseType(token, isOptional: returnTypeAllowed || !typeRequired); |
+ token = parseType( |
+ token, |
+ returnTypeAllowed || !typeRequired |
+ ? TypeContinuation.Optional |
+ : TypeContinuation.Required); |
if (typeRequired && beforeType == token) { |
reportRecoverableErrorCode(token, codeTypeRequired); |
} |
@@ -2104,7 +2138,7 @@ class Parser { |
if (type == null) { |
listener.handleNoType(name); |
} else { |
- parseType(type, isOptional: true); |
+ parseType(type, TypeContinuation.Optional); |
} |
Token token; |
if (optional('operator', name)) { |
@@ -2238,7 +2272,7 @@ class Parser { |
Token beginToken = token; |
listener.beginFunction(token); |
listener.handleModifiers(0); |
- token = parseType(token, isOptional: true); |
+ token = parseType(token, TypeContinuation.Optional); |
listener.beginFunctionName(token); |
token = parseIdentifier(token, IdentifierContext.functionExpressionName); |
listener.endFunctionName(beginToken, token); |