/* * Copyright 2000-2011 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 com.intellij.codeInsight.template.impl; import com.google.common.annotations.VisibleForTesting; import com.intellij.codeInsight.template.Expression; import com.intellij.codeInsight.template.Macro; import com.intellij.codeInsight.template.macro.MacroFactory; import com.intellij.lexer.Lexer; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.tree.IElementType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; @VisibleForTesting public class MacroParser { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.template.impl.MacroParser"); @NotNull public static Expression parse(@Nullable String expression) { if (StringUtil.isEmpty(expression)) { return new ConstantNode(""); } Lexer lexer = new MacroLexer(); lexer.start(expression); skipWhitespaces(lexer); return parseMacro(lexer, expression); } //----------------------------------------------------------------------------------- private static void advance(Lexer lexer) { lexer.advance(); skipWhitespaces(lexer); } //----------------------------------------------------------------------------------- private static void skipWhitespaces(Lexer lexer) { while (lexer.getTokenType() == MacroTokenType.WHITE_SPACE) { lexer.advance(); } } //----------------------------------------------------------------------------------- private static String getString(Lexer lexer, String expression) { return expression.substring(lexer.getTokenStart(), lexer.getTokenEnd()); } //----------------------------------------------------------------------------------- @SuppressWarnings({"HardCodedStringLiteral"}) private static Expression parseMacro(Lexer lexer, String expression) { IElementType tokenType = lexer.getTokenType(); String token = getString(lexer, expression); if (tokenType == MacroTokenType.STRING_LITERAL) { advance(lexer); return new ConstantNode(parseStringLiteral(token)); } if (tokenType != MacroTokenType.IDENTIFIER) { LOG.info("Bad macro syntax: Not identifier: " + token); advance(lexer); return new ConstantNode(""); } List<Macro> macros = MacroFactory.getMacros(token); if (macros.isEmpty()) { return parseVariable(lexer, expression); } advance(lexer); MacroCallNode macroCallNode = new MacroCallNode(macros.get(0)); if (lexer.getTokenType() == null) { return macroCallNode; } if (lexer.getTokenType() != MacroTokenType.LPAREN) { return macroCallNode; } advance(lexer); parseParameters(macroCallNode, lexer, expression); if (lexer.getTokenType() != MacroTokenType.RPAREN) { LOG.info("Bad macro syntax: ) expected: " + expression); } advance(lexer); return macroCallNode; } private static String parseStringLiteral(String token) { StringBuilder sb = new StringBuilder(token.length() - 2); int i = 1; while (i < token.length() - 1) { char c = token.charAt(i); if (c == '\\') { c = token.charAt(++i); if (c == 'n') sb.append('\n'); else if (c == 't') sb.append('\t'); else if (c == 'f') sb.append('\f'); else sb.append(c); } else { sb.append(c); } i++; } return sb.toString(); } private static void parseParameters(MacroCallNode macroCallNode, Lexer lexer, String expression) { if (lexer.getTokenType() != MacroTokenType.RPAREN) { while (lexer.getTokenType() != null) { Expression node = parseMacro(lexer, expression); macroCallNode.addParameter(node); if (lexer.getTokenType() == MacroTokenType.COMMA) { advance(lexer); } else { break; } } } } private static Expression parseVariable(Lexer lexer, String expression) { String variableName = getString(lexer, expression); advance(lexer); if (lexer.getTokenType() == null) { if (TemplateImpl.END.equals(variableName)) { return new EmptyNode(); } return new VariableNode(variableName, null); } if (lexer.getTokenType() != MacroTokenType.EQ) { return new VariableNode(variableName, null); } advance(lexer); Expression node = parseMacro(lexer, expression); return new VariableNode(variableName, node); } }