package edu.berkeley.nlp.PCFGLA; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; public class OptionParser { private final Map<String, Option> nameToOption = new HashMap<String, Option>(); private final Map<String, Field> nameToField = new HashMap<String, Field>(); private final Set<String> requiredOptions = new HashSet<String>(); private final Class optionsClass; private StringBuilder passedInOptions; public OptionParser(Class optionsClass) { this.optionsClass = optionsClass; for (Field field : optionsClass.getDeclaredFields()) { Option option = field.getAnnotation(Option.class); if (option == null) { continue; } nameToOption.put(option.name(), option); nameToField.put(option.name(), field); if (option.required()) { requiredOptions.add(option.name()); } } } private void usage() { System.err.println(); for (Option opt : nameToOption.values()) { System.err.printf("%-30s%s", opt.name(), opt.usage()); if (opt.required()) { System.err.printf(" [required]"); } System.err.println(); } System.err.printf("%-30shelp message\n", "-h"); System.err.println(); System.exit(2); } public Object parse(String[] args) { return parse(args, false, false); } public Object parse(String[] args, boolean failOnUnrecognized) { return parse(args, failOnUnrecognized, false); } public Object parse(String[] args, boolean failOnUnrecognized, boolean parrot) { if (parrot) System.out.println("Calling with " + Arrays.deepToString(args)); try { Set<String> seenOpts = new HashSet<String>(); passedInOptions = new StringBuilder("{"); Object options = optionsClass.newInstance(); for (int i = 0; i < args.length; ++i) { if (args[i].equals("-h")) { usage(); } Option opt = nameToOption.get(args[i]); if (opt == null) { if (failOnUnrecognized) { throw new RuntimeException("Did not recognize option " + args[i]); } else { System.err.println("WARNING: Did not recognize option " + args[i]); } continue; } seenOpts.add(args[i]); Field field = nameToField.get(args[i]); Class fieldType = field.getType(); // If option is boolean type then // we set the associate field to true if (fieldType == boolean.class) { field.setBoolean(options, true); passedInOptions.append(String.format(" %s => true", opt.name())); } // Otherwise look at next arg and // set field to that value // this will automatically // convert String to double or // whatever else { String value = args[i + 1]; if (value != null) value.trim(); passedInOptions.append(String.format(" %s => %s", opt.name(), value)); if (fieldType == int.class) { field.setInt(options, Integer.parseInt(value)); } else if (fieldType == double.class) { field.setDouble(options, Double.parseDouble(value)); } else if (fieldType == float.class) { field.setFloat(options, Float.parseFloat(value)); } else if (fieldType == short.class) { field.setFloat(options, Short.parseShort(value)); } else if (fieldType.isEnum()) { Object[] possibleValues = fieldType.getEnumConstants(); boolean found = false; for (Object possibleValue : possibleValues) { String enumName = ((Enum) possibleValue).name(); if (value.equals(enumName)) { field.set(options, possibleValue); found = true; break; } } if (!found) { if (failOnUnrecognized) { throw new RuntimeException("Unrecognized enumeration option " + value); } else { System.err .println("WARNING: Did not recognize option Enumeration option " + value); } } } else if (fieldType == String.class) { field.set(options, value); } else { try { Constructor constructor = fieldType .getConstructor(new Class[] { String.class }); field.set(options, constructor .newInstance((Object[]) (new String[] { value }))); } catch (NoSuchMethodException e) { System.err.println("Cannot construct object of type " + fieldType.getCanonicalName() + " from just a string"); } } ++i; } } passedInOptions.append(" }"); Set<String> optionsLeft = new HashSet<String>(requiredOptions); optionsLeft.removeAll(seenOpts); if (!optionsLeft.isEmpty()) { System.err.println("Failed to specify: " + optionsLeft); usage(); } return options; } catch (Exception e) { e.printStackTrace(); } return null; } public String getPassedInOptions() { return passedInOptions.toString(); } }