* @return the class member that was parsed, or {@code null} if what was found was not a valid
* class member
*/
protected ClassMember parseClassMember(String className) {
CommentAndMetadata commentAndMetadata = parseCommentAndMetadata();
Modifiers modifiers = parseModifiers();
if (matchesKeyword(Keyword.VOID)) {
TypeName returnType = parseReturnType();
if (matchesKeyword(Keyword.GET) && tokenMatchesIdentifier(peek())) {
validateModifiersForGetterOrSetterOrMethod(modifiers);
return parseGetter(
commentAndMetadata,
modifiers.getExternalKeyword(),
modifiers.getStaticKeyword(),
returnType);
} else if (matchesKeyword(Keyword.SET) && tokenMatchesIdentifier(peek())) {
validateModifiersForGetterOrSetterOrMethod(modifiers);
return parseSetter(
commentAndMetadata,
modifiers.getExternalKeyword(),
modifiers.getStaticKeyword(),
returnType);
} else if (matchesKeyword(Keyword.OPERATOR) && isOperator(peek())) {
validateModifiersForOperator(modifiers);
return parseOperator(commentAndMetadata, modifiers.getExternalKeyword(), returnType);
} else if (matchesIdentifier()
&& peek().matchesAny(
TokenType.OPEN_PAREN,
TokenType.OPEN_CURLY_BRACKET,
TokenType.FUNCTION)) {
validateModifiersForGetterOrSetterOrMethod(modifiers);
return parseMethodDeclarationAfterReturnType(
commentAndMetadata,
modifiers.getExternalKeyword(),
modifiers.getStaticKeyword(),
returnType);
} else {
//
// We have found an error of some kind. Try to recover.
//
if (matchesIdentifier()) {
if (peek().matchesAny(TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON)) {
//
// We appear to have a variable declaration with a type of "void".
//
reportErrorForNode(ParserErrorCode.VOID_VARIABLE, returnType);
return parseInitializedIdentifierList(
commentAndMetadata,
modifiers.getStaticKeyword(),
validateModifiersForField(modifiers),
returnType);
}
}
if (isOperator(currentToken)) {
//
// We appear to have found an operator declaration without the 'operator' keyword.
//
validateModifiersForOperator(modifiers);
return parseOperator(commentAndMetadata, modifiers.getExternalKeyword(), returnType);
}
reportErrorForToken(ParserErrorCode.EXPECTED_EXECUTABLE, currentToken);
return null;
}
} else if (matchesKeyword(Keyword.GET) && tokenMatchesIdentifier(peek())) {
validateModifiersForGetterOrSetterOrMethod(modifiers);
return parseGetter(
commentAndMetadata,
modifiers.getExternalKeyword(),
modifiers.getStaticKeyword(),
null);
} else if (matchesKeyword(Keyword.SET) && tokenMatchesIdentifier(peek())) {
validateModifiersForGetterOrSetterOrMethod(modifiers);
return parseSetter(
commentAndMetadata,
modifiers.getExternalKeyword(),
modifiers.getStaticKeyword(),
null);
} else if (matchesKeyword(Keyword.OPERATOR) && isOperator(peek())) {
validateModifiersForOperator(modifiers);
return parseOperator(commentAndMetadata, modifiers.getExternalKeyword(), null);
} else if (!matchesIdentifier()) {
if (isOperator(currentToken)) {
//
// We appear to have found an operator declaration without the 'operator' keyword.
//
validateModifiersForOperator(modifiers);
return parseOperator(commentAndMetadata, modifiers.getExternalKeyword(), null);
}
Token keyword = modifiers.getVarKeyword();
if (keyword == null) {
keyword = modifiers.getFinalKeyword();
}
if (keyword == null) {
keyword = modifiers.getConstKeyword();
}
if (keyword != null) {
//
// We appear to have found an incomplete field declaration.
//
reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
ArrayList<VariableDeclaration> variables = new ArrayList<VariableDeclaration>();
variables.add(new VariableDeclaration(null, null, createSyntheticIdentifier(), null, null));
return new FieldDeclaration(
commentAndMetadata.getComment(),
commentAndMetadata.getMetadata(),
null,
new VariableDeclarationList(null, null, keyword, null, variables),
expectSemicolon());
}
reportErrorForToken(ParserErrorCode.EXPECTED_CLASS_MEMBER, currentToken);
if (commentAndMetadata.getComment() != null || !commentAndMetadata.getMetadata().isEmpty()) {
//
// We appear to have found an incomplete declaration at the end of the class. At this point
// it consists of a metadata, which we don't want to loose, so we'll treat it as a method
// declaration with a missing name, parameters and empty body.
//
return new MethodDeclaration(
commentAndMetadata.getComment(),
commentAndMetadata.getMetadata(),
null,
null,
null,
null,
null,
createSyntheticIdentifier(),
new FormalParameterList(null, new ArrayList<FormalParameter>(), null, null, null),
new EmptyFunctionBody(createSyntheticToken(TokenType.SEMICOLON)));
}
return null;
} else if (tokenMatches(peek(), TokenType.PERIOD) && tokenMatchesIdentifier(peekAt(2))
&& tokenMatches(peekAt(3), TokenType.OPEN_PAREN)) {
return parseConstructor(
commentAndMetadata,
modifiers.getExternalKeyword(),
validateModifiersForConstructor(modifiers),
modifiers.getFactoryKeyword(),
parseSimpleIdentifier(),
getAndAdvance(),
parseSimpleIdentifier(),
parseFormalParameterList());
} else if (tokenMatches(peek(), TokenType.OPEN_PAREN)) {
SimpleIdentifier methodName = parseSimpleIdentifier();
FormalParameterList parameters = parseFormalParameterList();
if (matches(TokenType.COLON) || modifiers.getFactoryKeyword() != null
|| methodName.getName().equals(className)) {
return parseConstructor(
commentAndMetadata,
modifiers.getExternalKeyword(),
validateModifiersForConstructor(modifiers),
modifiers.getFactoryKeyword(),
methodName,
null,
null,
parameters);
}
validateModifiersForGetterOrSetterOrMethod(modifiers);
validateFormalParameterList(parameters);
return parseMethodDeclarationAfterParameters(
commentAndMetadata,
modifiers.getExternalKeyword(),
modifiers.getStaticKeyword(),
null,
methodName,
parameters);
} else if (peek().matchesAny(TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON)) {
if (modifiers.getConstKeyword() == null && modifiers.getFinalKeyword() == null
&& modifiers.getVarKeyword() == null) {
reportErrorForCurrentToken(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE);
}
return parseInitializedIdentifierList(
commentAndMetadata,
modifiers.getStaticKeyword(),
validateModifiersForField(modifiers),
null);
}
TypeName type = parseTypeName();
if (matchesKeyword(Keyword.GET) && tokenMatchesIdentifier(peek())) {
validateModifiersForGetterOrSetterOrMethod(modifiers);
return parseGetter(
commentAndMetadata,
modifiers.getExternalKeyword(),
modifiers.getStaticKeyword(),
type);
} else if (matchesKeyword(Keyword.SET) && tokenMatchesIdentifier(peek())) {
validateModifiersForGetterOrSetterOrMethod(modifiers);
return parseSetter(
commentAndMetadata,
modifiers.getExternalKeyword(),
modifiers.getStaticKeyword(),
type);
} else if (matchesKeyword(Keyword.OPERATOR) && isOperator(peek())) {
validateModifiersForOperator(modifiers);
return parseOperator(commentAndMetadata, modifiers.getExternalKeyword(), type);
} else if (!matchesIdentifier()) {
if (matches(TokenType.CLOSE_CURLY_BRACKET)) {
//
// We appear to have found an incomplete declaration at the end of the class. At this point
// it consists of a type name, so we'll treat it as a field declaration with a missing
// field name and semicolon.
//
return parseInitializedIdentifierList(
commentAndMetadata,
modifiers.getStaticKeyword(),
validateModifiersForField(modifiers),
type);
}
if (isOperator(currentToken)) {
//
// We appear to have found an operator declaration without the 'operator' keyword.
//
validateModifiersForOperator(modifiers);
return parseOperator(commentAndMetadata, modifiers.getExternalKeyword(), type);
}
//
// We appear to have found an incomplete declaration before another declaration.
// At this point it consists of a type name, so we'll treat it as a field declaration
// with a missing field name and semicolon.
//
reportErrorForToken(ParserErrorCode.EXPECTED_CLASS_MEMBER, currentToken);
try {
lockErrorListener();
return parseInitializedIdentifierList(
commentAndMetadata,
modifiers.getStaticKeyword(),
validateModifiersForField(modifiers),
type);
} finally {
unlockErrorListener();
}
} else if (tokenMatches(peek(), TokenType.OPEN_PAREN)) {
SimpleIdentifier methodName = parseSimpleIdentifier();
FormalParameterList parameters = parseFormalParameterList();
if (methodName.getName().equals(className)) {
reportErrorForNode(ParserErrorCode.CONSTRUCTOR_WITH_RETURN_TYPE, type);
return parseConstructor(
commentAndMetadata,
modifiers.getExternalKeyword(),
validateModifiersForConstructor(modifiers),
modifiers.getFactoryKeyword(),
methodName,
null,
null,
parameters);
}
validateModifiersForGetterOrSetterOrMethod(modifiers);
validateFormalParameterList(parameters);
return parseMethodDeclarationAfterParameters(
commentAndMetadata,
modifiers.getExternalKeyword(),
modifiers.getStaticKeyword(),
type,
methodName,
parameters);
} else if (tokenMatches(peek(), TokenType.OPEN_CURLY_BRACKET)) {
// We have found "TypeName identifier {", and are guessing that this is a getter without the
// keyword 'get'.
validateModifiersForGetterOrSetterOrMethod(modifiers);
reportErrorForCurrentToken(ParserErrorCode.MISSING_GET);
currentToken = injectToken(new SyntheticKeywordToken(Keyword.GET, currentToken.getOffset()));
return parseGetter(
commentAndMetadata,
modifiers.getExternalKeyword(),
modifiers.getStaticKeyword(),
type);
}
return parseInitializedIdentifierList(
commentAndMetadata,
modifiers.getStaticKeyword(),
validateModifiersForField(modifiers),
type);
}