blob: 017e2602230000d962649c79bb11eee9a6f754df [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.lang.parser.parsing.statements.typeDefinitions;
import com.intellij.lang.PsiBuilder;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.GroovyBundle;
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes;
import org.jetbrains.plugins.groovy.lang.parser.GroovyParser;
import org.jetbrains.plugins.groovy.lang.parser.parsing.auxiliary.Separators;
import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.typeDefinitions.members.EnumConstant;
import org.jetbrains.plugins.groovy.lang.parser.parsing.types.TypeParameters;
import org.jetbrains.plugins.groovy.lang.parser.parsing.util.ParserUtils;
/**
* @autor: Dmitry.Krasilschikov
* @date: 16.03.2007
*/
/*
* TypeDefinition ::= ClassDefinition
* | InterfaceDefinition
* | EnumDefinition
* | AnnotationDefinition
*/
public class TypeDefinition {
public static IElementType parseAfterModifiers(PsiBuilder builder, GroovyParser parser) {
if (builder.getTokenType() == GroovyTokenTypes.kCLASS) {
builder.advanceLexer();
if (parseAfterKeyword(builder, parser, ClassType.CLASS)) {
return GroovyElementTypes.CLASS_DEFINITION;
}
}
if (builder.getTokenType() == GroovyTokenTypes.kINTERFACE) {
builder.advanceLexer();
if (parseAfterKeyword(builder, parser, ClassType.INTERFACE)) {
return GroovyElementTypes.INTERFACE_DEFINITION;
}
}
if (builder.getTokenType() == GroovyTokenTypes.kENUM) {
builder.advanceLexer();
if (parseAfterKeyword(builder, parser, ClassType.ENUM)) {
return GroovyElementTypes.ENUM_DEFINITION;
}
}
if (builder.getTokenType() == GroovyTokenTypes.kTRAIT) {
builder.advanceLexer();
if (parseAfterKeyword(builder, parser, ClassType.TRAIT)) {
return GroovyElementTypes.TRAIT_DEFINITION;
}
}
if (builder.getTokenType() == GroovyTokenTypes.mAT) {
builder.advanceLexer();
if (builder.getTokenType() == GroovyTokenTypes.kINTERFACE) {
builder.advanceLexer();
if (parseAfterKeyword(builder, parser, ClassType.ANNOTATION)) {
return GroovyElementTypes.ANNOTATION_DEFINITION;
}
}
}
return GroovyElementTypes.WRONGWAY;
}
private static boolean parseAfterKeyword(final PsiBuilder builder, final GroovyParser parser, final ClassType type) {
if (builder.getTokenType() != GroovyTokenTypes.mIDENT) {
builder.error(GroovyBundle.message("identifier.expected"));
return false;
}
final String name = builder.getTokenText();
assert name != null;
builder.advanceLexer();
ParserUtils.getToken(builder, GroovyTokenTypes.mNLS);
TypeParameters.parse(builder);
ParserUtils.getToken(builder, GroovyTokenTypes.mNLS);
ReferenceElement.parseReferenceList(builder, GroovyTokenTypes.kEXTENDS, GroovyElementTypes.EXTENDS_CLAUSE, type);
ParserUtils.getToken(builder, GroovyTokenTypes.mNLS);
ReferenceElement.parseReferenceList(builder, GroovyTokenTypes.kIMPLEMENTS, GroovyElementTypes.IMPLEMENTS_CLAUSE, type);
ParserUtils.getToken(builder, GroovyTokenTypes.mNLS);
if (builder.getTokenType() == GroovyTokenTypes.mLCURLY) {
if (type == ClassType.ENUM) {
parseEnumBody(builder, name, parser);
}
else {
parseBody(builder, name, parser, type == ClassType.ANNOTATION);
}
}
else {
builder.error(GroovyBundle.message("lcurly.expected"));
}
return true;
}
public static IElementType parseBody(@NotNull PsiBuilder builder,
@Nullable String className,
@NotNull GroovyParser parser,
final boolean isInAnnotation) {
//allow errors
PsiBuilder.Marker cbMarker = builder.mark();
if (!ParserUtils.getToken(builder, GroovyTokenTypes.mLCURLY)) {
builder.error(GroovyBundle.message("lcurly.expected"));
cbMarker.rollbackTo();
return GroovyElementTypes.WRONGWAY;
}
parseMembers(builder, className, parser, isInAnnotation);
ParserUtils.getToken(builder, GroovyTokenTypes.mRCURLY, GroovyBundle.message("rcurly.expected"));
cbMarker.done(GroovyElementTypes.CLASS_BODY);
return GroovyElementTypes.CLASS_BODY;
}
private static void parseMembers(@NotNull PsiBuilder builder,
@Nullable String className,
@NotNull GroovyParser parser,
final boolean isInAnnotation) {
Separators.parse(builder);
while (!builder.eof() && builder.getTokenType() != GroovyTokenTypes.mRCURLY) {
if (!parser.parseDeclaration(builder, true, isInAnnotation, className)) {
builder.advanceLexer();
builder.error(GroovyBundle.message("separator.or.rcurly.expected"));
}
if (builder.getTokenType() == GroovyTokenTypes.mRCURLY) {
break;
}
if (!Separators.parse(builder)) {
builder.error(GroovyBundle.message("separator.or.rcurly.expected"));
}
}
}
private static IElementType parseEnumBody(@NotNull PsiBuilder builder,
@NotNull String enumName,
@NotNull GroovyParser parser) {
PsiBuilder.Marker ebMarker = builder.mark();
if (!ParserUtils.getToken(builder, GroovyTokenTypes.mLCURLY)) {
ebMarker.rollbackTo();
return GroovyElementTypes.WRONGWAY;
}
ParserUtils.getToken(builder, GroovyTokenTypes.mNLS);
if (EnumConstant.parseConstantList(builder, parser)) {
if (!ParserUtils.lookAhead(builder, GroovyTokenTypes.mRCURLY)) {
ParserUtils.getToken(builder, TokenSet.create(GroovyTokenTypes.mNLS, GroovyTokenTypes.mSEMI), GroovyBundle.message("separator.or.rcurly.expected"));
}
}
parseMembers(builder, enumName, parser, false);
ParserUtils.getToken(builder, GroovyTokenTypes.mRCURLY, GroovyBundle.message("rcurly.expected"));
ebMarker.done(GroovyElementTypes.ENUM_BODY);
return GroovyElementTypes.ENUM_BODY;
}
}