Cleanup parsing method to make it less generic.

git-svn-id: file:///humgen/gsa-scr1/gsa-engineering/svn_contents/trunk@619 348d0f76-0448-11de-a6fe-93d51630548a
This commit is contained in:
hanna 2009-05-07 16:21:17 +00:00
parent d725c6cf1c
commit 4f85062004
3 changed files with 123 additions and 130 deletions

View File

@ -142,34 +142,6 @@ class ArgumentDefinitions implements Iterable<ArgumentDefinition> {
}
};
static AliasProvider ShortNameAliasProvider = new AliasProvider() {
/**
* Short names can come in the form -Ofoo.txt, -O foo.txt, or -out (multi-character short name).
* Given the argument name and built-in provided, see if these can be formed into some other argument
* name.
* @param argument Name of the argument, as parsed. For a short name, will be a single letter.
* @param value Value of the argument, as parsed.
* @return Any potential aliases for the given shortname.
*/
public List<String> getAliases( String argument, String value ) {
List<String> aliases = new ArrayList<String>();
aliases.add(argument+value);
aliases.add(argument);
return aliases;
}
/**
* Is the value part of the given alias, or something separate that should be treated as an argument value.
* @param alias The alias to use.
* @param argument The parsed argument.
* @param value The parsed value.
* @return True if this alias should be used instead of the given value.
*/
public boolean doesAliasConsumeValue( String alias, String argument, String value ) {
return alias.equals(argument + value);
}
};
/**
* Find all required definitions.
*/
@ -289,24 +261,3 @@ interface DefinitionMatcher {
*/
boolean matches( ArgumentDefinition definition, Object key );
}
/**
* A way to get alternate names for the argument given the recognized name and value.
*/
interface AliasProvider {
/**
* Give all alternate names for the given argument / value pair. The aliases should
* be returned in 'preferred order'.
* @param argument The argument.
* @param value The value.
* @return All possible names.
*/
List<String> getAliases( String argument, String value );
/**
* True if this alias 'consumes' the value, meaning that the argument + value together
* represent some other alias.
* @return True if the value should still be used. False otherwise.
*/
boolean doesAliasConsumeValue( String alias, String argument, String value );
}

View File

@ -10,8 +10,6 @@ import java.lang.reflect.Modifier;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.ArrayList;
import java.util.List;
import java.util.Collection;
@ -60,10 +58,8 @@ public class ParsingEngine {
protected static Logger logger = Logger.getLogger(ParsingEngine.class);
public ParsingEngine() {
parsingMethods.add( new ParsingMethod(Pattern.compile("\\s*--([\\w\\.]+)\\s*"), ArgumentDefinitions.FullNameDefinitionMatcher) );
parsingMethods.add( new ParsingMethod(Pattern.compile("\\s*-([\\w\\.])([\\w\\.\\/:\\-]*)\\s*"),
ArgumentDefinitions.ShortNameDefinitionMatcher,
ArgumentDefinitions.ShortNameAliasProvider) );
parsingMethods.add( new FullNameParsingMethod() );
parsingMethods.add( new ShortNameParsingMethod() );
}
/**
@ -242,7 +238,7 @@ public class ParsingEngine {
*/
private boolean isArgumentForm( String token ) {
for( ParsingMethod parsingMethod: parsingMethods ) {
if( parsingMethod.pattern.matcher(token).matches() )
if( parsingMethod.matches(token) )
return true;
}
@ -259,7 +255,7 @@ public class ParsingEngine {
throw new IllegalArgumentException( "Token is not recognizable as an argument: " + token );
for( ParsingMethod parsingMethod: parsingMethods ) {
if( parsingMethod.matches( argumentDefinitions, token ) )
if( parsingMethod.matches( token ) )
return parsingMethod.match( argumentDefinitions, token, position );
}
@ -413,79 +409,6 @@ public class ParsingEngine {
}
}
}
/**
* Holds a pattern, along with how to get to the argument definitions that could match that pattern.
*/
private class ParsingMethod {
public final Pattern pattern;
public final DefinitionMatcher definitionMatcher;
public final AliasProvider aliasProvider;
public ParsingMethod( Pattern pattern, DefinitionMatcher definitionMatcher ) {
this( pattern, definitionMatcher, null );
}
public ParsingMethod( Pattern pattern, DefinitionMatcher definitionMatcher, AliasProvider aliasProvider ) {
this.pattern = pattern;
this.definitionMatcher = definitionMatcher;
this.aliasProvider = aliasProvider;
}
public boolean matches( ArgumentDefinitions definitions, String token ) {
Matcher matcher = pattern.matcher(token);
return matcher.matches();
}
public ArgumentMatch match( ArgumentDefinitions definitions, String token, int position ) {
Matcher matcher = pattern.matcher(token);
// Didn't match? Must be bad input.
if( !matcher.matches() )
throw new IllegalArgumentException( String.format("Unable to parse token %s with pattern %s", token, pattern.pattern()) );
// If the argument is valid, parse out the argument and value (if present).
String argument = matcher.group(1);
String value = null;
if( matcher.groupCount() > 1 && matcher.group(2).trim().length() > 0)
value = matcher.group(2).trim();
// If an alias provider has been provided, determine the possible list of argument names that this
// argument / value pair can represent.
ArgumentDefinition bestMatchArgumentDefinition = null;
if( aliasProvider != null ) {
List<String> aliases = aliasProvider.getAliases( argument, value );
String bestAlias = null;
for( String alias: aliases ) {
if( definitions.findArgumentDefinition(alias,definitionMatcher) != null ) {
bestAlias = alias;
bestMatchArgumentDefinition = definitions.findArgumentDefinition(alias,definitionMatcher);
break;
}
}
// Couldn't find anything appropriate? The aliases should be in best-to-worst order, so
if( bestAlias == null ) {
bestAlias = aliases.get(0);
}
if( aliasProvider.doesAliasConsumeValue(bestAlias,argument,value) ) value = null;
argument = bestAlias;
}
else
bestMatchArgumentDefinition = definitions.findArgumentDefinition( argument, definitionMatcher );
// Try to find a matching argument. If found, label that as the match. If not found, add the argument
// with a null definition.
ArgumentMatch argumentMatch = new ArgumentMatch( argument, bestMatchArgumentDefinition, position );
if( value != null )
argumentMatch.addValue( position, value );
return argumentMatch;
}
}
}
/**

View File

@ -0,0 +1,119 @@
package org.broadinstitute.sting.utils.cmdLine;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.List;
import java.util.ArrayList;
/**
* Holds a pattern, along with how to get to the argument definitions that could match that pattern.
*/
interface ParsingMethod {
/**
* Can the given token be parsed by this parsing method?
* @param token Token to validate.
* @return True if the given token matches.
*/
public abstract boolean matches( String token );
/**
* Find the best match for a given token at a given position from among the provided
* argument definitions.
* @param definitions List of argument definitions.
* @param token The token from the command line to match. Should be validated using
* ParsingMethod's matches() tester.
* @param position Position at which this command-line argument occurs. Will be used
* for validation later.
* @return An argument match. Definition field will be populated if a match was found or
* empty if no appropriate definition could be found.
*/
public abstract ArgumentMatch match( ArgumentDefinitions definitions, String token, int position );
}
/**
* Instructions for how to parse a command-line argument passed by full name into a match.
*/
class FullNameParsingMethod implements ParsingMethod {
private static final Pattern pattern = Pattern.compile("\\s*--([\\w\\.\\-]+)\\s*");
private static final DefinitionMatcher definitionMatcher = ArgumentDefinitions.FullNameDefinitionMatcher;
public boolean matches( String token ) {
Matcher matcher = pattern.matcher(token);
return matcher.matches();
}
public ArgumentMatch match( ArgumentDefinitions definitions, String token, int position ) {
// If the argument is valid, parse out the argument.
Matcher matcher = pattern.matcher(token);
// Didn't match? Must be bad input.
if( !matcher.matches() )
throw new IllegalArgumentException( String.format("Unable to parse token %s with pattern %s", token, pattern.pattern()) );
String argument = matcher.group(1).trim();
// Find the most appropriate argument definition for the given argument.
ArgumentDefinition argumentDefinition = definitions.findArgumentDefinition( argument, definitionMatcher );
// Try to find a matching argument. If found, label that as the match. If not found, add the argument
// with a null definition.
ArgumentMatch argumentMatch = new ArgumentMatch( argument, argumentDefinition, position );
return argumentMatch;
}
}
/**
* Instructions for how to parse a command-line argument passed by short name into a match.
*/
class ShortNameParsingMethod implements ParsingMethod {
private static final Pattern standalonePattern = Pattern.compile("\\s*-([\\w\\-]+)\\s*");
private static final Pattern embeddedValuePattern = Pattern.compile("\\s*-([\\w\\.])([\\w/:\\.\\-]+)\\s*");
private static final DefinitionMatcher definitionMatcher = ArgumentDefinitions.ShortNameDefinitionMatcher;
public boolean matches( String token ) {
return standalonePattern.matcher(token).matches() || embeddedValuePattern.matcher(token).matches();
}
public ArgumentMatch match( ArgumentDefinitions definitions, String token, int position ) {
// Didn't match? Must be bad input.
if( !matches(token) )
throw new IllegalArgumentException( String.format("Unable to parse token %s with pattern %s", token, embeddedValuePattern.pattern()) );
// Build the best possible standalone match given the available data.
Matcher standaloneMatcher = standalonePattern.matcher(token);
ArgumentMatch standaloneMatch = null;
if( standaloneMatcher.matches() ) {
String argument = standaloneMatcher.group(1).trim();
ArgumentDefinition argumentDefinition = definitions.findArgumentDefinition(argument,definitionMatcher);
standaloneMatch = new ArgumentMatch( argument, argumentDefinition, position );
}
// Build the best possible embedded value match given the available data.
Matcher embeddedValueMatcher = embeddedValuePattern.matcher(token);
ArgumentMatch embeddedValueMatch = null;
if( embeddedValueMatcher.matches() ) {
String argument = embeddedValueMatcher.group(1).trim();
String value = embeddedValueMatcher.group(2).trim();
ArgumentDefinition argumentDefinition = definitions.findArgumentDefinition(argument,definitionMatcher);
embeddedValueMatch = new ArgumentMatch( argument, argumentDefinition, position );
if( embeddedValueMatch != null && value != null )
embeddedValueMatch.addValue( position, value );
}
// Prefer the standalone match...
ArgumentMatch bestMatch = standaloneMatch;
// ...But if the embedded value match is clearly better, choose it as the best match instead.
if( (standaloneMatch == null || standaloneMatch.definition == null) &&
(embeddedValueMatch != null && embeddedValueMatch.definition != null) )
bestMatch = embeddedValueMatch;
return bestMatch;
}
}