package com.innovatian.idea.powershell.lang.parser; import com.innovatian.idea.powershell.lang.lexer.PsElementType; import com.innovatian.idea.powershell.lang.lexer.PsTokenSets; import com.innovatian.idea.powershell.lang.lexer.PsTokenTypes; import com.innovatian.idea.powershell.lang.parser.parsing.ParserUtils; import com.innovatian.idea.powershell.lang.parser.parsing.statements.expressions.ConditionalExpression; import com.innovatian.idea.powershell.lang.parser.parsing.statements.expressions.ExpressionStatement; import com.intellij.lang.ASTNode; import com.intellij.lang.PsiBuilder; import com.intellij.lang.PsiParser; import com.intellij.psi.tree.IElementType; import org.jetbrains.annotations.NotNull; public class PsParser implements PsiParser, PsElementTypes { @NotNull public ASTNode parse(IElementType root, PsiBuilder builder) { builder.setDebugMode(true); //CompilationUnit.parse(builder, this); IElementType elementType = builder.getTokenType(); PsiBuilder.Marker rootMarker = builder.mark(); while (!builder.eof()) { parseSourceElement(builder); } rootMarker.done(root); return builder.getTreeBuilt(); } public void parseBlockBody(PsiBuilder builder) { if (PsTokenTypes.SEMI.equals(builder.getTokenType()) || PsTokenTypes.NLS.equals(builder.getTokenType())) { Separators.parse(builder); } boolean result = parseStatement(builder, false); while (result && (PsTokenTypes.SEMI.equals(builder.getTokenType()) || PsTokenTypes.NLS.equals(builder.getTokenType()))) { Separators.parse(builder); result = parseStatement(builder, false); } cleanAfterError(builder); Separators.parse(builder); } protected void cleanAfterError(PsiBuilder builder) { int i = 0; PsiBuilder.Marker em = builder.mark(); while (!builder.eof() && !(PsTokenTypes.NLS.equals(builder.getTokenType()) || PsTokenTypes.RCURLY.equals(builder.getTokenType()) || PsTokenTypes.SEMI.equals(builder.getTokenType())) ) { builder.advanceLexer(); i++; } if (i > 0) { em.error("separator.or.rcurly.expected"); } else { em.drop(); } } public void parseSourceElement(PsiBuilder builder) { if (StringConstructorExpression.parse(builder, this) != WRONGWAY) { return; } if (ExpressionStatement.parse(builder, this)) { return; } if (builder.getTokenType() == PsTokenTypes.ML_COMMENT) { builder.advanceLexer(); builder.advanceLexer(); } else { parseStatement(builder); } } public void parseStatement(PsiBuilder builder) { final IElementType firstToken = builder.getTokenType(); if (PsTokenTypes.IF.equals(firstToken)) { parseIfStatement(builder); return; } if (firstToken == null) return; builder.advanceLexer(); } public IElementType parse(PsiBuilder builder) { if (EXPSTRING_LITERAL == builder.getTokenType()) { return StringConstructorExpression.parse(builder, this); } if (LPAREN == builder.getTokenType()) { return parenthesizedExprParse(builder); } if (LCURLY == builder.getTokenType()) { return parseClosableBlock(builder); } if (PsTokenSets.CONSTANTS.contains(builder.getTokenType())) { ParserUtils.eatElement(builder, LITERAL); return LITERAL; } return WRONGWAY; } public PsElementType parenthesizedExprParse(PsiBuilder builder) { PsiBuilder.Marker marker = builder.mark(); ParserUtils.getToken(builder, LPAREN); if (!AssignmentExpression.parse(builder, this)) { builder.error("expression.expected"); } ParserUtils.getToken(builder, NLS); if (!ParserUtils.getToken(builder, RPAREN, "rparen.expected")) { while (!builder.eof() && NLS != builder.getTokenType() && SEMI != builder.getTokenType() && RPAREN != builder.getTokenType()) { builder.error("rparen.expected"); builder.advanceLexer(); } ParserUtils.getToken(builder, RPAREN); } marker.done(PARENTHESIZED_EXPRESSION); return PARENTHESIZED_EXPRESSION; } public boolean parseIfStatement(PsiBuilder builder) { //allow error messages PsiBuilder.Marker ifStmtMarker = builder.mark(); if (!ParserUtils.getToken(builder, PsTokenTypes.IF)) { ifStmtMarker.rollbackTo(); builder.error("if.expected"); return false; } if (!ParserUtils.getToken(builder, PsTokenTypes.LPAREN, "lparen.expected")) { // ifStmtMarker.done(IF_STATEMENT); // return IF_STATEMENT; ifStmtMarker.drop(); return false; } if (!ConditionalExpression.parse(builder, this)) { builder.error("expression.expected"); } ParserUtils.getToken(builder, PsTokenTypes.NLS); if (!ParserUtils.getToken(builder, PsTokenTypes.RPAREN, "rparen.expected")) { while (!builder.eof()) { final IElementType type = builder.getTokenType(); if (PsTokenTypes.NLS == type || PsTokenTypes.RPAREN == type || PsTokenTypes.LCURLY == type || PsTokenTypes.RCURLY == type) { break; } builder.advanceLexer(); builder.error("rparen.expected"); } if (!ParserUtils.getToken(builder, PsTokenTypes.RPAREN)) { ifStmtMarker.done(PsElementTypes.IF_STATEMENT); return true; } } PsiBuilder.Marker warn = builder.mark(); if (builder.getTokenType() == PsTokenTypes.NLS) { ParserUtils.getToken(builder, PsTokenTypes.NLS); } if (!parseStatement(builder, true)) { warn.rollbackTo(); builder.error("expression.expected"); ifStmtMarker.done(PsElementTypes.IF_STATEMENT); return true; } else { warn.drop(); } PsiBuilder.Marker rb = builder.mark(); if (PsTokenTypes.ELSE.equals(builder.getTokenType()) || (Separators.parse(builder) && builder.getTokenType() == PsTokenTypes.ELSE)) { rb.drop(); ParserUtils.getToken(builder, PsTokenTypes.ELSE); warn = builder.mark(); if (builder.getTokenType() == PsTokenTypes.NLS) { ParserUtils.getToken(builder, PsTokenTypes.NLS); } if (!parseStatement(builder, true)) { warn.rollbackTo(); builder.error("expression.expected"); ifStmtMarker.done(PsElementTypes.IF_STATEMENT); return true; } else { warn.drop(); } ifStmtMarker.done(PsElementTypes.IF_STATEMENT); return true; } else { rb.rollbackTo(); ifStmtMarker.done(PsElementTypes.IF_STATEMENT); return true; } } public boolean parseStatement(PsiBuilder builder, boolean isBlockStatementNeeded) { if (isBlockStatementNeeded && PsTokenTypes.LCURLY.equals(builder.getTokenType())) { return parseBlockStatement(builder); } if (PsTokenTypes.IF.equals(builder.getTokenType())) { return parseIfStatement(builder); } /* if (PsTokenTypes.SWITCH.equals(builder.getTokenType())) { return SwitchStatement.parse(builder, this); } if (PsTokenTypes.TRY.equals(builder.getTokenType())) { return TryCatchStatement.parse(builder, this); } if (PsTokenTypes.WHILE.equals(builder.getTokenType())) { return parseWhileStatement(builder); } if (PsTokenTypes.FOR.equals(builder.getTokenType())) { return parseForStatement(builder); } */ // Possible errors if (PsTokenTypes.ELSE.equals(builder.getTokenType())) { ParserUtils.wrapError(builder, "else.without.if"); parseStatement(builder, true); return true; } if (PsTokenTypes.CATCH.equals(builder.getTokenType())) { ParserUtils.wrapError(builder, "catch.without.try"); parseStatement(builder, false); return true; } if (PsTokenTypes.FINALLY.equals(builder.getTokenType())) { ParserUtils.wrapError(builder, "finally.without.try"); parseStatement(builder, false); return true; } if (PsTokenTypes.IDENT.equals(builder.getTokenType())) { ParserUtils.wrapError(builder, "identifier.expected"); parseStatement(builder, false); return true; } /*if (PsTokenTypes.CASE.equals(builder.getTokenType())) { // case statements in powershell are literals PsiBuilder.Marker marker = builder.mark(); SwitchStatement.parseCaseLabel(builder, this); marker.error(GroovyBundle.message("case.without.switch")); parseStatement(builder, false); return true; } */ return false; } public boolean parseOpenBlock(PsiBuilder builder) { return parseOpenBlockInDifferentContext(builder, false); } public boolean parseBlockStatement(PsiBuilder builder) { return parseOpenBlockInDifferentContext(builder, true); } public boolean parseOpenBlockInDifferentContext(PsiBuilder builder, boolean isBlockStatement) { PsiBuilder.Marker blockStatementMarker = builder.mark(); PsiBuilder.Marker marker = builder.mark(); if (!ParserUtils.getToken(builder, LCURLY)) { marker.drop(); blockStatementMarker.drop(); return false; } ParserUtils.getToken(builder, NLS); parseBlockBody(builder); while (!builder.eof() && !RCURLY.equals(builder.getTokenType())) { builder.error("expression.expected"); builder.advanceLexer(); } ParserUtils.getToken(builder, RCURLY, "rcurly.expected"); marker.done(OPEN_BLOCK); if (isBlockStatement) { blockStatementMarker.done(BLOCK_STATEMENT); } else { blockStatementMarker.drop(); } return true; } public PsElementType parseClosableBlock(PsiBuilder builder) { PsiBuilder.Marker marker = builder.mark(); if (!ParserUtils.getToken(builder, LCURLY)) { marker.drop(); return WRONGWAY; } ParserUtils.getToken(builder, NLS); parseBlockBody(builder); ParserUtils.getToken(builder, RCURLY, "rcurly.expected"); marker.done(CLOSABLE_BLOCK); return CLOSABLE_BLOCK; } }