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

org.ocpsoft.rewrite.util.ParseTools Maven / Gradle / Ivy

/*
 * Copyright 2011 Lincoln Baxter, III
 * 
 * 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.ocpsoft.rewrite.util;

import java.util.Arrays;
import java.util.Stack;

import org.ocpsoft.common.util.Assert;

/**
 * @author Lincoln Baxter, III
 * 
 */
public abstract class ParseTools
{
   private static final char ESCAPE_CHAR = '\\';

   /**
    * Return the index of the terminating character in the group, excluding markers.
    */
   public static CapturingGroup balancedCapture(final char[] chars, final int startPos, final int endPos,
            final CaptureType type)
   {
      Assert.notNull(chars, "Character input array must not be null.");
      Assert.assertTrue(startPos >= 0, "Start position must be greater than zero.");
      Assert.assertTrue(startPos < (chars.length - 1),
               "Start position must be at least one character before the array upper bound.");
      Assert.assertTrue(endPos > 0, "End position must be greater than zero.");
      Assert.assertTrue(endPos < chars.length, "End position must be less than or equal to the array upper bound.");
      Assert.assertTrue(startPos < endPos, "Start position must be less than end position.");

      Assert.assertTrue(chars[startPos] == type.getBegin(), "Character at starting position was [" + chars[startPos]
               + "] but expected [" + type.getBegin() + "]");

      if (isEscaped(chars, startPos))
      {
         throw new IllegalArgumentException(
                  "Character at starting position is escaped, and cannot be used in capturing a group.");
      }

      char begin = type.getBegin();
      char end = type.getEnd();

      int cursor = startPos + 1;
      Stack beginPositions = new Stack();
      beginPositions.push(cursor);
      while ((cursor <= endPos) && (beginPositions.size() > 0))
      {
         char character = chars[cursor];
         if (character == end)
         {
            if (!isEscaped(chars, cursor))
            {
               beginPositions.pop();
            }
         }
         else if (character == begin)
         {
            if (!isEscaped(chars, cursor))
            {
               beginPositions.push(cursor);
            }
         }

         if (beginPositions.size() == 0)
         {
            break;
         }
         cursor++;
      }

      if (beginPositions.size() > 0)
      {
         throw new IllegalArgumentException(
                  "Unclosed capturing group at index [" + beginPositions.peek() + "] of [" + new String(chars) + "]");
      }

      return new CapturingGroup(chars, startPos, cursor);
   }

   /**
    * Return true if the character at the given cursor is escaped; otherwise, return false.
    */
   public static boolean isEscaped(final char[] chars, final int cursor)
   {
      Assert.notNull(chars, "Character input array must not be null.");
      Assert.assertTrue(cursor >= 0, "Start position must be greater than zero.");
      Assert.assertTrue(cursor < (chars.length),
               "Start position must be within the array upper bound.");

      if ((cursor > 0) && (chars[cursor - 1] == ESCAPE_CHAR))
      {
         if ((cursor == 1) || ((cursor > 1) && (chars[cursor - 2] != ESCAPE_CHAR)))
         {
            return true;
         }
      }
      return false;
   }

   public static class CapturingGroup
   {
      private final char[] chars;
      private final int start;
      private final int end;

      public CapturingGroup(final char[] chars, final int start, final int end)
      {
         this.chars = chars;
         this.start = start;
         this.end = end;
      }

      public int getStart()
      {
         return start;
      }

      public int getEnd()
      {
         return end;
      }

      public char[] getCaptured()
      {
         return Arrays.copyOfRange(chars, start + 1, end);
      }

      @Override
      public String toString()
      {
         return "CapturingGroup [start=" + start + ", end=" + end + "]";
      }
   }

   public enum CaptureType
   {
      BRACE('{', '}'), BRACKET('[', ']'), PAREN('(', ')'), REGEX('/', '/');

      private char begin;
      private char end;

      private CaptureType(final char begin, final char end)
      {
         this.begin = begin;
         this.end = end;
      }

      public char getBegin()
      {
         return begin;
      }

      public char getEnd()
      {
         return end;
      }
   }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy