All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.plugins.groovy.lang.parser.parsing.statements.expressions.primary.CompoundStringExpression Maven / Gradle / Ivy

Go to download

A packaging of the IntelliJ Community Edition groovy-psi library. This is release number 1 of trunk branch 142.

The newest version!
/*
 * Copyright 2000-2014 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 org.jetbrains.plugins.groovy.lang.parser.parsing.statements.expressions.primary;

import com.intellij.lang.PsiBuilder;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.GroovyBundle;
import org.jetbrains.plugins.groovy.lang.lexer.GroovyElementType;
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes;
import org.jetbrains.plugins.groovy.lang.parser.GroovyParser;
import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.blocks.OpenOrClosableBlock;
import org.jetbrains.plugins.groovy.lang.parser.parsing.statements.expressions.arithmetic.PathExpression;
import org.jetbrains.plugins.groovy.lang.parser.parsing.util.ParserUtils;

/**
 * @author ilyas
 */
public class CompoundStringExpression {
  private static final Logger LOG = Logger.getInstance(CompoundStringExpression.class);
  private final PsiBuilder myBuilder;
  private final GroovyParser myParser;
  private final boolean myForRefExpr;
  private final IElementType myBegin;
  private final IElementType myContent;
  private final IElementType myEnd;
  private final IElementType mySimpleLiteral;
  private final GroovyElementType myCompoundLiteral;
  private final String myMessage;

  private CompoundStringExpression(PsiBuilder builder,
                                  GroovyParser parser,
                                  boolean forRefExpr,
                                  IElementType begin,
                                  IElementType content,
                                  IElementType end,
                                  IElementType literal,
                                  GroovyElementType compoundLiteral,
                                  String message) {

    myBuilder = builder;
    myParser = parser;
    myForRefExpr = forRefExpr;
    myBegin = begin;
    myContent = content;
    myEnd = end;
    mySimpleLiteral = literal;
    myCompoundLiteral = compoundLiteral;
    myMessage = message;
  }

  private boolean parse() {
    PsiBuilder.Marker marker = myBuilder.mark();
    final PsiBuilder.Marker marker2 = myBuilder.mark();
    LOG.assertTrue(ParserUtils.getToken(myBuilder, myBegin));


    if (mySimpleLiteral != null && myBuilder.getTokenType() == myEnd) {
      myBuilder.advanceLexer();
      finishSimpleLiteral(marker, marker2);
      return true;
    }

    if (myBuilder.getTokenType() == myContent) {
      final PsiBuilder.Marker contentMarker = myBuilder.mark();
      myBuilder.advanceLexer();
      if (myBuilder.getTokenType() == GroovyTokenTypes.mDOLLAR || mySimpleLiteral == null) {
        contentMarker.done(GroovyElementTypes.GSTRING_CONTENT);
      }
      else {
        contentMarker.drop();
      }
    }
    else {
      processContent();
    }

    boolean hasInjection = myBuilder.getTokenType() == GroovyTokenTypes.mDOLLAR;
    while (myBuilder.getTokenType() == GroovyTokenTypes.mDOLLAR) {
      parseInjection();
      processContent();
    }

    if (!ParserUtils.getToken(myBuilder, myEnd)) {
      myBuilder.error(myMessage);
    }

    if (hasInjection || mySimpleLiteral == null) {
      marker2.drop();
      marker.done(myCompoundLiteral);
    }
    else {
      finishSimpleLiteral(marker, marker2);
    }
    return hasInjection;
  }

  private void processContent() {
    PsiBuilder.Marker marker = myBuilder.mark();
    if (myBuilder.getTokenType() == myContent) {
      myBuilder.advanceLexer();
    }
    else {
      myBuilder.mark().done(myContent);
    }
    marker.done(GroovyElementTypes.GSTRING_CONTENT);
  }

  private void finishSimpleLiteral(PsiBuilder.Marker marker, PsiBuilder.Marker marker2) {
    marker2.done(mySimpleLiteral);
    if (myForRefExpr) {
      marker.drop();
    }
    else {
      marker.done(GroovyElementTypes.LITERAL);
    }
  }

  /**
   * Parses heredoc's content in GString
   *
   * @return nothing
   */
  private boolean parseInjection() {
    if (myBuilder.getTokenType() != GroovyTokenTypes.mDOLLAR) return false;

    final PsiBuilder.Marker injection = myBuilder.mark();
    ParserUtils.getToken(myBuilder, GroovyTokenTypes.mDOLLAR);

    if (myBuilder.getTokenType() == GroovyTokenTypes.mIDENT || myBuilder.getTokenType() == GroovyTokenTypes.kTHIS) {
      PathExpression.parse(myBuilder, myParser);
    }
    else if (myBuilder.getTokenType() == GroovyTokenTypes.mLCURLY) {
      OpenOrClosableBlock.parseClosableBlock(myBuilder, myParser);
    }
    else {
      ParserUtils.wrapError(myBuilder, GroovyBundle.message("identifier.or.block.expected"));
    }

    injection.done(GroovyElementTypes.GSTRING_INJECTION);
    return true;
  }

  /**
   * Groovy lexer does not smart enough to understand whether a regex contents injections or not. So the parser should do this job.
   * We create additional marker2 for the case of absence of injections. In this case resulting tree is as follows:
   *
   * Regex
   *   mRegexLiteral    (mDollarSlashRegexLiteral)
   *     mRegexBegin    (........................)
   *     mRegexContent  (........................)
   *     mRegexEnd      (........................)
   *
   * This tree emulates tree of simple GrLiteralImpl structure so we can use regexes where simple strings are expected.
   *
   * @return true if there are any injections
   */
  public static boolean parse(@NotNull PsiBuilder builder,
                              @NotNull GroovyParser parser,
                              boolean forRefExpr,
                              @NotNull IElementType begin,
                              @NotNull IElementType content,
                              @NotNull IElementType end,
                              @Nullable IElementType literal,
                              @NotNull GroovyElementType compoundLiteral,
                              @NotNull String message) {
    return new CompoundStringExpression(builder, parser, forRefExpr, begin, content, end, literal, compoundLiteral, message).parse();
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy