/* * Copyright 2013-2017 consulo.io * * 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 consulo.csharp.lang.parser.macro; import consulo.csharp.lang.parser.SharedParsingHelpers; import consulo.csharp.lang.psi.CSharpMacroElements; import consulo.csharp.lang.psi.CSharpMacroTokens; import com.intellij.lang.PsiBuilder; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.TokenSet; /** * @author VISTALL * @since 18.12.13. */ public class MacroParsing implements CSharpMacroTokens, CSharpMacroElements { private static final TokenSet COND_STOPPERS = TokenSet.create(MACRO_ENDIF_KEYWORD, MACRO_ELSE_KEYWORD, MACRO_ELIF_KEYWORD); public static boolean parse(PsiBuilder builder) { PsiBuilder.Marker mark = builder.mark(); IElementType token = builder.getTokenType(); if(token == MACRO_DEFINE_KEYWORD || token == MACRO_UNDEF_KEYWORD) { builder.advanceLexer(); if(builder.getTokenType() == MACRO_VALUE) { builder.advanceLexer(); } else { builder.error("Identifier expected"); } skipUntilStop(builder); mark.done(token == MACRO_UNDEF_KEYWORD ? MACRO_UNDEF : MACRO_DEFINE); return true; } else if(token == MACRO_IF_KEYWORD) { PsiBuilder.Marker condBlock = builder.mark(); PsiBuilder.Marker startMarker = builder.mark(); builder.advanceLexer(); PsiBuilder.Marker parse = MacroExpressionParsing.parse(builder); if(parse == null) { builder.error("Expression expected"); } SharedParsingHelpers.expect(builder, MACRO_STOP, null); startMarker.done(MACRO_BLOCK_START); parseAndDoneUntilCondStoppers(builder, condBlock); while(!builder.eof()) { if(builder.getTokenType() == MACRO_ELIF_KEYWORD) { parseElIf(builder, startMarker); } else if(builder.getTokenType() == MACRO_ELSE_KEYWORD) { parseElse(builder, startMarker); } else if(builder.getTokenType() == MACRO_ENDIF_KEYWORD) { break; } } if(builder.getTokenType() == MACRO_ENDIF_KEYWORD) { PsiBuilder.Marker endIfMarker = builder.mark(); builder.advanceLexer(); SharedParsingHelpers.expect(builder, MACRO_STOP, null); endIfMarker.done(MACRO_BLOCK_STOP); } else { builder.error("'#endif' expected"); } mark.done(MACRO_IF); return true; } else if(token == MACRO_REGION_KEYWORD) { PsiBuilder.Marker startMarker = builder.mark(); builder.advanceLexer(); skipUntilStop(builder); startMarker.done(MACRO_BLOCK_START); while(!builder.eof()) { if(builder.getTokenType() == MACRO_ENDREGION_KEYWORD) { break; } builder.advanceLexer(); } if(builder.getTokenType() == MACRO_ENDREGION_KEYWORD) { PsiBuilder.Marker endIfMarker = builder.mark(); builder.advanceLexer(); skipUntilStop(builder); endIfMarker.done(MACRO_BLOCK_STOP); } else { builder.error("'#endregion' expected"); } mark.done(MACRO_BLOCK); return true; } else if(token == MACRO_ENDREGION_KEYWORD) { builder.advanceLexer(); builder.error("'#endregion' without '#region'"); skipUntilStop(builder); mark.done(MACRO_BLOCK_STOP); return true; } else if(token == MACRO_ENDIF_KEYWORD) { builder.advanceLexer(); builder.error("'#endif' without '#if'"); skipUntilStop(builder); mark.done(MACRO_BLOCK_STOP); return true; } else { builder.advanceLexer(); mark.drop(); return false; } } private static void parseElse(PsiBuilder builder, PsiBuilder.Marker parentMarker) { PsiBuilder.Marker mark = builder.mark(); PsiBuilder.Marker headerMarker = builder.mark(); if(parentMarker == null) { builder.error("#if block not opened"); } builder.advanceLexer(); SharedParsingHelpers.expect(builder, MACRO_STOP, null); headerMarker.done(MACRO_BLOCK_START); parseAndDoneUntilCondStoppers(builder, mark); } private static void parseAndDoneUntilCondStoppers(PsiBuilder builder, PsiBuilder.Marker marker) { while(!builder.eof()) { if(COND_STOPPERS.contains(builder.getTokenType())) { break; } MacroParsing.parse(builder); } marker.done(MACRO_IF_CONDITION_BLOCK); } private static void parseElIf(PsiBuilder builder, PsiBuilder.Marker parentMarker) { PsiBuilder.Marker mark = builder.mark(); PsiBuilder.Marker headerMarker = builder.mark(); if(parentMarker == null) { builder.error("#if block not opened"); } builder.advanceLexer(); PsiBuilder.Marker parse = MacroExpressionParsing.parse(builder); if(parse == null) { builder.error("Expression expected"); } SharedParsingHelpers.expect(builder, MACRO_STOP, null); headerMarker.done(MACRO_BLOCK_START); while(!builder.eof()) { if(COND_STOPPERS.contains(builder.getTokenType())) { break; } MacroParsing.parse(builder); } mark.done(MACRO_IF_CONDITION_BLOCK); } private static void skipUntilStop(PsiBuilder builder) { while(!builder.eof()) { if(builder.getTokenType() == MACRO_STOP) { builder.advanceLexer(); break; } else { builder.advanceLexer(); } } } }