package org.fandev.lang.fan.parsing.statements.typeDefinitions.members; import com.intellij.lang.PsiBuilder; import com.intellij.psi.tree.IElementType; import org.fandev.lang.fan.FanElementTypes; import org.fandev.lang.fan.FanTokenTypes; import org.fandev.lang.fan.FanBundle; import static org.fandev.lang.fan.FanElementTypes.METHOD_BODY; import static org.fandev.lang.fan.FanElementTypes.METHOD_DEFINITION; import static org.fandev.lang.fan.FanTokenTypes.*; import org.fandev.lang.fan.parsing.auxiliary.facets.Facet; import org.fandev.lang.fan.parsing.util.ParserUtils; import org.fandev.lang.fan.parsing.statements.Block; import org.fandev.lang.fan.parsing.statements.declaration.DeclarationType; import java.util.Set; import java.util.HashSet; /** * <p>Grammar Definition:<ul> * <li><slotDefs> := <slotDef>*</li> * <li><slotDef> := <fieldDef> | <methodDef> | <ctorDef></li> * </ul></p> * * @author Dror Bereznitsky * @date Jan 10, 2009 4:25:33 PM */ public class SlotDefinition { public static boolean parse(final PsiBuilder builder, final DeclarationType type, final boolean isBuiltInType) { ParserUtils.removeNls(builder); // TODO: find a better way than rollbacking PsiBuilder.Marker rb = builder.mark(); // All slot types have facets Facet.parse(builder); // All slot types have modifiers final Set<IElementType> modifiers = new HashSet<IElementType>(); while (FanTokenTypes.ALL_SLOT_MODIFIERS.contains(builder.getTokenType())) { modifiers.add(builder.getTokenType()); ParserUtils.advanceNoNls(builder); if (type == DeclarationType.MIXIN && FanTokenTypes.ONCE_KEYWORD == builder.getTokenType()) { rb.error(FanBundle.message("mixins.cannot.declare.once.methods")); rb = builder.mark(); } } // Find out what kind of slot: field, method, constructor, static init if (LBRACE.equals(builder.getTokenType())) { // expecting static {...} rb.rollbackTo(); final PsiBuilder.Marker staticInitMark = builder.mark(); if (!STATIC_KEYWORD.equals(builder.getTokenType())) { staticInitMark.error(FanBundle.message("expecting.keyword.static")); return false; } final PsiBuilder.Marker idMark = builder.mark(); ParserUtils.advanceNoNls(builder); idMark.done(FanElementTypes.NAME_ELEMENT); if (!LBRACE.equals(builder.getTokenType())) { staticInitMark.error(FanBundle.message("expecting.static")); return false; } Block.parse(builder, METHOD_BODY); staticInitMark.done(METHOD_DEFINITION); return true; } else if (NEW_KEYWORD.equals(builder.getTokenType())) { // New keyword enforce constructor if (type == DeclarationType.MIXIN) { rb.error(FanBundle.message("mixins.cannot.declare.constructors")); return false; } else if (type == DeclarationType.ENUM) { if (!modifiers.contains(FanTokenTypes.PRIVATE_KEYWORD)) { rb.error(FanBundle.message("enums.must.have.private.constructors")); return false; } } rb.rollbackTo(); return ConstructorDefinition.parse(builder, isBuiltInType); } else if (ParserUtils.lookAheadForElement(builder, LPAR, LBRACE, SEMICOLON, NLS, COLON_EQ)) { // Found a ( before <eos> so it's a method rb.rollbackTo(); return MethodDefinition.parse(builder, isBuiltInType); } else { rb.rollbackTo(); return FieldDefinition.parse(builder); } } }