blob: c8e3dc4202206d7064b35ed35d3f90a415a68cc4 [file] [log] [blame]
/*
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
* Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package proguard.util;
import java.util.List;
/**
* This StringParser can create StringMatcher instances for regular expressions.
* The regular expressions are either presented as a list, or they are
* interpreted as comma-separated lists, optionally prefixed with '!' negators.
* If an entry with a negator matches, a negative match is returned, without
* considering any subsequent entries in the list. The creation of StringMatcher
* instances for the entries is delegated to the given StringParser.
*
* @author Eric Lafortune
*/
public class ListParser implements StringParser
{
private final StringParser stringParser;
/**
* Creates a new ListParser that parses individual elements in the
* comma-separated list with the given StringParser.
*/
public ListParser(StringParser stringParser)
{
this.stringParser = stringParser;
}
// Implementations for StringParser.
public StringMatcher parse(String regularExpression)
{
// Does the regular expression contain a ',' list separator?
return parse(ListUtil.commaSeparatedList(regularExpression));
}
/**
* Creates a StringMatcher for the given regular expression, which can
* be a list of optionally negated simple entries.
* <p>
* An empty list results in a StringMatcher that matches any string.
*/
public StringMatcher parse(List regularExpressions)
{
StringMatcher listMatcher = null;
// Loop over all simple regular expressions, backward, creating a
// linked list of matchers.
for (int index = regularExpressions.size()-1; index >= 0; index--)
{
String regularExpression = (String)regularExpressions.get(index);
StringMatcher entryMatcher = parseEntry(regularExpression);
// Prepend the entry matcher.
listMatcher =
listMatcher == null ?
(StringMatcher)entryMatcher :
isNegated(regularExpression) ?
(StringMatcher)new AndMatcher(entryMatcher, listMatcher) :
(StringMatcher)new OrMatcher(entryMatcher, listMatcher);
}
return listMatcher != null ? listMatcher : new ConstantMatcher(true);
}
// Small utility methods.
/**
* Creates a StringMatcher for the given regular expression, which is a
* an optionally negated simple expression.
*/
private StringMatcher parseEntry(String regularExpression)
{
// Wrap the matcher if the regular expression starts with a '!' negator.
return isNegated(regularExpression) ?
new NotMatcher(stringParser.parse(regularExpression.substring(1))) :
stringParser.parse(regularExpression);
}
/**
* Returns whether the given simple regular expression is negated.
*/
private boolean isNegated(String regularExpression)
{
return regularExpression.length() > 0 &&
regularExpression.charAt(0) == '!';
}
/**
* A main method for testing name matching.
*/
public static void main(String[] args)
{
try
{
System.out.println("Regular expression ["+args[0]+"]");
ListParser parser = new ListParser(new NameParser());
StringMatcher matcher = parser.parse(args[0]);
for (int index = 1; index < args.length; index++)
{
String string = args[index];
System.out.print("String ["+string+"]");
System.out.println(" -> match = "+matcher.matches(args[index]));
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
}