package org.fandev.lang.fan.parsing.util; import com.intellij.lang.PsiBuilder; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.TokenSet; import org.fandev.lang.fan.FanBundle; import org.fandev.lang.fan.FanElementTypes; import static org.fandev.lang.fan.FanTokenTypes.*; /** * @author Dror Bereznitsky * @date Jan 6, 2009 2:33:06 PM */ public class ParserUtils { public static boolean getToken(final PsiBuilder builder, final IElementType elem) { if (elem.equals(builder.getTokenType())) { builder.advanceLexer(); return true; } return false; } public static boolean getToken(final PsiBuilder builder, final TokenSet tokens) { if (tokens.contains(builder.getTokenType())) { builder.advanceLexer(); return true; } return false; } public static boolean getToken(final PsiBuilder builder, final IElementType elem, final String errorMsg) { if (elem.equals(builder.getTokenType())) { builder.advanceLexer(); return true; } else { if (errorMsg != null) { builder.error(errorMsg); } return false; } } public static boolean getToken(final PsiBuilder builder, final TokenSet tokens, final String errorMsg) { if (tokens.contains(builder.getTokenType())) { builder.advanceLexer(); return true; } else { if (errorMsg != null) { builder.error(errorMsg); } return false; } } public static IElementType firstAfter(final PsiBuilder builder, final IElementType... elems) { final TokenSet ignored = TokenSet.create(elems); IElementType result; if (ignored.contains(builder.getTokenType())) { final PsiBuilder.Marker rb = builder.mark(); while (!builder.eof() && ignored.contains(builder.getTokenType())) { builder.advanceLexer(); } result = builder.getTokenType(); rb.rollbackTo(); } else { result = builder.getTokenType(); } return result; } public static boolean lookAhead(final PsiBuilder builder, final IElementType... elems) { if (!elems[0].equals(builder.getTokenType())) { return false; } if (elems.length == 1) { return true; } final PsiBuilder.Marker rb = builder.mark(); builder.advanceLexer(); int i = 1; while (!builder.eof() && i < elems.length && elems[i].equals(builder.getTokenType())) { builder.advanceLexer(); i++; } rb.rollbackTo(); return i == elems.length; } public static boolean lookAheadForElement(final PsiBuilder builder, final IElementType elem, final IElementType... stopElements) { final TokenSet stopElem = TokenSet.create(stopElements); return lookAheadForElement(builder, elem, stopElem); } public static boolean lookAheadForElement(final PsiBuilder builder, final IElementType elem, final TokenSet stopElem) { final PsiBuilder.Marker rb = builder.mark(); while (!builder.eof() && !(elem == builder.getTokenType()) && !stopElem.contains(builder.getTokenType())) { builder.advanceLexer(); } if (builder.eof()) { rb.rollbackTo(); return false; } else if (stopElem.contains(builder.getTokenType())) { rb.rollbackTo(); return false; } else { rb.rollbackTo(); return true; } } public static IElementType eatElement(final PsiBuilder builder, final IElementType elem) { final PsiBuilder.Marker marker = builder.mark(); builder.advanceLexer(); marker.done(elem); return elem; } public static void advanceToBlockEnd(final PsiBuilder builder) { advanceToBlockEnd(builder, LBRACE, RBRACE); } public static void advanceToArgumentsEnd(final PsiBuilder builder) { advanceToBlockEnd(builder, LPAR, RPAR); } public static void advanceToArrayEnd(final PsiBuilder builder) { advanceToBlockEnd(builder, LBRACKET, RBRACKET); } public static void advanceToBlockEnd(final PsiBuilder builder, final IElementType opening, final IElementType closing) { int openLeft = 1; while (!builder.eof() && openLeft > 0) { builder.advanceLexer(); if (builder.getTokenType() == opening) { openLeft++; } else if (builder.getTokenType() == closing) { openLeft--; } } builder.advanceLexer(); } public static boolean advanceTo(final PsiBuilder builder, final TokenSet stopper) { while (!builder.eof() && !stopper.contains(builder.getTokenType())) { builder.advanceLexer(); } return stopper.contains(builder.getTokenType()); } public static void advanceNoNls(final PsiBuilder builder) { builder.advanceLexer(); removeNls(builder); } public static void removeNls(final PsiBuilder builder) { while (NLS.equals(builder.getTokenType())) { builder.advanceLexer(); } } public static void cleanAfterErrorInBlock(final PsiBuilder builder) { final PsiBuilder.Marker em = builder.mark(); advanceToBlockEnd(builder); em.error(FanBundle.message("separator.expected")); } public static void cleanAfterErrorInArguments(final PsiBuilder builder) { final PsiBuilder.Marker em = builder.mark(); advanceToArgumentsEnd(builder); em.error(FanBundle.message("separator.expected")); } public static void cleanAfterErrorInArray(final PsiBuilder builder) { final PsiBuilder.Marker em = builder.mark(); advanceToArrayEnd(builder); em.error(FanBundle.message("separator.expected")); } public static boolean parseName(final PsiBuilder builder) { // id if (!IDENTIFIER_TOKENS_SET.contains(builder.getTokenType())) { builder.error(FanBundle.message("identifier.expected")); return false; } final PsiBuilder.Marker idMark = builder.mark(); builder.advanceLexer(); idMark.done(FanElementTypes.NAME_ELEMENT); return true; } public static void removeStoppers(final PsiBuilder builder, final TokenSet stopper, final TokenSet reccuring) { if (stopper.contains(builder.getTokenType())) { builder.advanceLexer(); } while (reccuring.contains(builder.getTokenType())) { builder.advanceLexer(); } } }