* not given
* @return the class declaration that was parsed
*/
private CompilationUnitMember parseClassDeclaration(CommentAndMetadata commentAndMetadata,
Token abstractKeyword) {
Token keyword = expectKeyword(Keyword.CLASS);
if (matchesIdentifier()) {
Token next = peek();
if (tokenMatches(next, TokenType.LT)) {
next = skipTypeParameterList(next);
if (next != null && tokenMatches(next, TokenType.EQ)) {
return parseClassTypeAlias(commentAndMetadata, abstractKeyword, keyword);
}
} else if (tokenMatches(next, TokenType.EQ)) {
return parseClassTypeAlias(commentAndMetadata, abstractKeyword, keyword);
}
}
SimpleIdentifier name = parseSimpleIdentifier();
String className = name.getName();
TypeParameterList typeParameters = null;
if (matches(TokenType.LT)) {
typeParameters = parseTypeParameterList();
}
//
// Parse the clauses. The parser accepts clauses in any order, but will generate errors if they
// are not in the order required by the specification.
//
ExtendsClause extendsClause = null;
WithClause withClause = null;
ImplementsClause implementsClause = null;
boolean foundClause = true;
while (foundClause) {
if (matchesKeyword(Keyword.EXTENDS)) {
if (extendsClause == null) {
extendsClause = parseExtendsClause();
if (withClause != null) {
reportErrorForToken(ParserErrorCode.WITH_BEFORE_EXTENDS, withClause.getWithKeyword());
} else if (implementsClause != null) {
reportErrorForToken(
ParserErrorCode.IMPLEMENTS_BEFORE_EXTENDS,
implementsClause.getKeyword());
}
} else {
reportErrorForToken(ParserErrorCode.MULTIPLE_EXTENDS_CLAUSES, extendsClause.getKeyword());
parseExtendsClause();
}
} else if (matchesKeyword(Keyword.WITH)) {
if (withClause == null) {
withClause = parseWithClause();
if (implementsClause != null) {
reportErrorForToken(
ParserErrorCode.IMPLEMENTS_BEFORE_WITH,
implementsClause.getKeyword());
}
} else {
reportErrorForToken(ParserErrorCode.MULTIPLE_WITH_CLAUSES, withClause.getWithKeyword());
parseWithClause();
// TODO(brianwilkerson) Should we merge the list of applied mixins into a single list?
}
} else if (matchesKeyword(Keyword.IMPLEMENTS)) {
if (implementsClause == null) {
implementsClause = parseImplementsClause();
} else {
reportErrorForToken(
ParserErrorCode.MULTIPLE_IMPLEMENTS_CLAUSES,
implementsClause.getKeyword());
parseImplementsClause();
// TODO(brianwilkerson) Should we merge the list of implemented classes into a single list?
}
} else {
foundClause = false;
}
}
if (withClause != null && extendsClause == null) {
reportErrorForToken(ParserErrorCode.WITH_WITHOUT_EXTENDS, withClause.getWithKeyword());
}
//
// Look for and skip over the extra-lingual 'native' specification.
//
NativeClause nativeClause = null;
if (matchesString(NATIVE) && tokenMatches(peek(), TokenType.STRING)) {
nativeClause = parseNativeClause();
}
//
// Parse the body of the class.
//
Token leftBracket = null;
List<ClassMember> members = null;
Token rightBracket = null;
if (matches(TokenType.OPEN_CURLY_BRACKET)) {
leftBracket = expect(TokenType.OPEN_CURLY_BRACKET);
members = parseClassMembers(className, getEndToken(leftBracket));
rightBracket = expect(TokenType.CLOSE_CURLY_BRACKET);
} else {