public static void assertMatches(Automaton automaton, List<String> valid, List<String> invalid) {
	String[] validStrings = valid.toArray(new String[0]);
	String[] invalidStrings = invalid.toArray(new String[0]);
	assertThat(matchSamples(automaton, validStrings), containsInAnyOrder(validStrings));
	assertThat(matchSamples(automaton, invalidStrings), empty());
} public static CharProvider chars(String sample) {
	return new StringCharProvider(sample, 0);
} public static List<String> invalid1() {
	return Arrays.asList(
		"b",
		"abb",
		"aaaabb",
		"aaaabaabb"
		);
} public static List<String> invalid2() {
	return Arrays.asList(
		"",
		"b",
		"ab",
		"baaa"
		);
} public static List<String> invalid3() {
	return Arrays.asList(
		"0110",
		"abcd"
		);
} public static List<String> invalid4() {
	return Arrays.asList(
		"",
		"b",
		"bbb",
		"baaaaba"
		);
} public static List<String> invalid5() {
	return Arrays.asList(
		"b",
		"abb",
		"aaaabb",
		"aaaabaabb"
		);
} public static List<String> invalid8() {
	return Arrays.asList(
		"",
		"a"
		);
} public static List<String> invalid9() {
	return Arrays.asList(
		"",
		"a"
		);
} public static Set<String> matchPrefixes(Automaton a, String... samples) {
	PrefixCollector collector = new PrefixCollector();
	AutomatonMatcher matcher = a.matcher().withListener(collector);
	for (String sample : samples) {
		matcher.applyTo(chars(sample));
	}
	return new LinkedHashSet<String>(collector.getMatchedTexts());
} public static Set<String> matchSamples(Automaton a, String... samples) {
	MatchCollector collector = new MatchCollector();
	AutomatonMatcher matcher = a.matcher().withListener(collector);
	for (String sample : samples) {
		matcher.applyTo(chars(sample));
	}
	return new LinkedHashSet<String>(collector.getMatchedTexts());
} public static GenericAutomaton nfa1() {
	State state0 = new State(DefaultTokenType.ACCEPT);
	State state1 = new State(DefaultTokenType.ACCEPT);
	State state2 = new State();
	State state3 = new State();

	state0.addTransition(new ExactTransition('a', state1));
	state0.addTransition(new ExactTransition('a', state2));

	state1.addTransition(new ExactTransition('a', state1));
	state1.addTransition(new ExactTransition('a', state2));

	state2.addTransition(new ExactTransition('b', state1));
	state2.addTransition(new ExactTransition('b', state3));

	state3.addTransition(new ExactTransition('a', state1));
	state3.addTransition(new ExactTransition('a', state2));

	return new GenericAutomaton(state0);
} public static GenericAutomaton nfa2() {
	State state0 = new State();
	State state1 = new State(DefaultTokenType.ACCEPT);
	State state2 = new State();
	State state3 = new State();
	State state4 = new State();

	state0.addTransition(new ExactTransition('a', state1));
	state0.addTransition(new RangeTransition('a', 'b', state2));
	state0.addTransition(new ExactTransition('b', state3));

	state1.addTransition(new ExactTransition('a', state1));
	state1.addTransition(new ExactTransition('a', state2));

	state2.addTransition(new ExactTransition('b', state2));
	state2.addTransition(new ExactTransition('b', state3));
	state2.addTransition(new ExactTransition('b', state4));

	state3.addTransition(new ExactTransition('b', state3));
	state3.addTransition(new ExactTransition('b', state3));
	state3.addTransition(new RangeTransition('a', 'b', state4));

	return new GenericAutomaton(state0);
} public static GenericAutomaton nfa3() {
	State state1 = new State();
	State state2 = new State();
	State state3 = new State();
	State state4 = new State();
	State state6 = new State();
	State state7 = new State();
	State state8 = new State();
	State state9 = new State();
	State state10 = new State(DefaultTokenType.ACCEPT);

	state1.addTransition(new ExactTransition('0', state2));
	state1.addTransition(new ExactTransition('1', state6));

	state2.addTransition(new ExactTransition('0', state7));
	state2.addTransition(new ExactTransition('1', state3));

	state3.addTransition(new ExactTransition('0', state8));
	state3.addTransition(new ExactTransition('1', state4));

	state4.addTransition(new ExactTransition('0', state9));
	state4.addTransition(new ExactTransition('1', state10));

	state6.addTransition(new RangeTransition('0', '1', state7));

	state7.addTransition(new RangeTransition('0', '1', state8));

	state8.addTransition(new RangeTransition('0', '1', state10));

	return new GenericAutomaton(state1);
} public static GenericAutomaton nfa4() {
	State state0 = new State();
	State state1 = new State();
	State state2 = new State();
	State state3 = new State(DefaultTokenType.ACCEPT);

	state0.addTransition(new ExactTransition('a', state1));
	state0.addTransition(new RangeTransition('a', 'b', state2));

	state1.addTransition(new ExactTransition('a', state2));
	state1.addTransition(new ExactTransition('b', state3));

	state2.addTransition(new ExactTransition('a', state1));
	state2.addTransition(new ExactTransition('a', state2));
	state2.addTransition(new ExactTransition('b', state3));

	return new GenericAutomaton(state0);
} public static GenericAutomaton nfa5() {
	State state0 = new State(A);
	State state1 = new State(B);
	State state2 = new State();
	State state3 = new State();

	state0.addTransition(new ExactTransition('a', state1));
	state0.addTransition(new ExactTransition('a', state2));

	state1.addTransition(new ExactTransition('a', state1));
	state1.addTransition(new ExactTransition('a', state2));

	state2.addTransition(new ExactTransition('b', state1));
	state2.addTransition(new ExactTransition('b', state3));

	state3.addTransition(new ExactTransition('a', state1));
	state3.addTransition(new ExactTransition('a', state2));

	return new GenericAutomaton(state0);
} public static GenericAutomaton nfa8() {
	State state0 = new State();
	State state1 = new State();
	State state2 = new State(DefaultTokenType.ACCEPT);
	State state3 = new State();
	State state4 = new State(DefaultTokenType.ACCEPT);

	state0.addTransition(new ExactTransition('a', state1));
	state0.addTransition(new ExactTransition('a', state3));

	state1.addTransition(new ExactTransition('a', state2));

	state3.addTransition(new ExactTransition('a', state3));
	state3.addTransition(new ExactTransition('b', state4));

	return new GenericAutomaton(state0);
} public static GenericAutomaton nfa9() {
	State state0 = new State();
	State state1 = new State();
	State state2 = new State(DefaultTokenType.ACCEPT);
	State state3 = new State();
	State state4 = new State(DefaultTokenType.ACCEPT);

	state0.addTransition(new ExactTransition('a', state1));
	state0.addTransition(new ExactTransition('a', state3));

	state1.addTransition(new ExactTransition('a', state2));

	state2.addTransition(new ExactTransition('c', state0));

	state3.addTransition(new ExactTransition('a', state3));
	state3.addTransition(new ExactTransition('b', state4));

	return new GenericAutomaton(state0);
} public static List<String> valid1() {
	return Arrays.asList(
		"",
		"a",
		"aa",
		"aaa",
		"aaab",
		"aaaab",
		"aaaba",
		"aaaaba",
		"aaabab",
		"aaaabab",
		"aaababab",
		"aaaababab",
		"aaaabaaabaaaaaab"
		);
} public static List<String> valid2() {
	return Arrays.asList(
		"a",
		"aa",
		"aaa",
		"aaaa",
		"aaaaa"
		);
} public static List<String> valid3() {
	List<String> input = new ArrayList<String>(16);
	for (int i = 0; i < 16; i++) {
		StringBuilder buffer = new StringBuilder();
		buffer.append((i & 0x08) / 0x08);
		buffer.append((i & 0x04) / 0x04);
		buffer.append((i & 0x02) / 0x02);
		buffer.append((i & 0x01) / 0x01);
		input.add(buffer.toString());
	}
	input.remove("0110");
	return input;
} public static List<String> valid4() {
	return Arrays.asList(
		"bb",
		"aab",
		"aaaaaaab",
		"bab",
		"baaaab"
		);
} public static List<String> valid5() {
	return Arrays.asList(
		"",
		"a",
		"aa",
		"aaa",
		"aaab",
		"aaaab",
		"aaaba",
		"aaaaba",
		"aaabab",
		"aaaabab",
		"aaababab",
		"aaaababab",
		"aaaabaaabaaaaaab"
		);
} public static List<String> valid8() {
	return Arrays.asList(
		"aa",
		"aab"
		);
} public static List<String> valid9() {
	return Arrays.asList(
		"aa",
		"aab",
		"aacaa",
		"aacaab",
		"aacaacaa",
		"aacaacaab"
		);
} public static List<String> withOutEmpty(List<String> list) {
	List<String> result = new LinkedList<String>(list);
	result.remove("");
	return result;
} public static GenericAutomaton withTokens(GenericAutomaton a) {
	for (State state : a.findAllStates()) {
		if (state.getType() == DefaultTokenType.ACCEPT || state.getType() == DefaultTokenType.IGNORE) {
			state.setType(REMAINDER);
		}
	}
	return a;
} public static GenericAutomaton match(char value) {
	State s = new State();
	State e = new State(DefaultTokenType.ACCEPT);

	s.addTransition(new ExactTransition(value, e));
	return new GenericAutomaton(s);
} public static GenericAutomaton matchAlternatives(GenericAutomaton... as) {
	return matchAlternatives(Arrays.asList(as));
} public static GenericAutomaton matchAnyChar() {
	State s = new State();
	State e = new State(DefaultTokenType.ACCEPT);
	s.addTransition(new RangeTransition(Character.MIN_VALUE, Character.MAX_VALUE, e));
	return new GenericAutomaton(s);
} public static GenericAutomaton matchAnyOf(char... chars) {
	State s = new State();
	State e = new State(DefaultTokenType.ACCEPT);
	for (char c : chars) {
		s.addTransition(new ExactTransition(c, e));
	}
	return new GenericAutomaton(s);
} public static GenericAutomaton matchComplement(GenericAutomaton a) {
	GenericAutomaton automaton = a.eliminateEpsilons().determinize().totalizeAndClean().minimize();
	for (State current : automaton.findAllStates()) {
		if (current.accept()) {
			current.setType(null);
		} else if (current.error()) {
			current.setType(DefaultTokenType.IGNORE);
			current.addTransition(new RangeTransition(Character.MIN_VALUE, Character.MAX_VALUE, current));
		} else {
			current.setType(DefaultTokenType.IGNORE);
		}
	}
	return automaton;
} public static GenericAutomaton matchConcatenation(GenericAutomaton... as) {
	return matchConcatenation(Arrays.asList(as));
} public static GenericAutomaton matchConjunctive(GenericAutomaton... as) {
	return matchConjunctive(Arrays.asList(as));
} public static GenericAutomaton matchEmpty() {
	State s = new State(DefaultTokenType.ACCEPT);
	return new GenericAutomaton(s);
} public static GenericAutomaton matchFixedLoop(GenericAutomaton a, int count) {
	GenericAutomaton[] as = copyOf(a, new GenericAutomaton[count], count);
	return matchConcatenation(as);
} public static GenericAutomaton matchNothing() {
	State s = new State();
	return new GenericAutomaton(s);
} public static GenericAutomaton matchOptional(GenericAutomaton a) {
	State s = new State(DefaultTokenType.ACCEPT);
	s.addTransition(new EpsilonTransition(a.getStart()));
	return new GenericAutomaton(s);
} public static GenericAutomaton matchRangeLoop(GenericAutomaton a, int start, int end) {
	if (start == end) {
		return matchFixedLoop(a, start);
	} else if (start == 0) {
		return matchUpToN(a, end);
	} else {
		GenericAutomaton aFixed = matchFixedLoop(a.clone(), start);
		GenericAutomaton aUpToN = matchUpToN(a, end - start);
		GenericAutomaton matchConcatenation = matchConcatenation(aFixed, aUpToN);
		return matchConcatenation;
	}
} public static GenericAutomaton matchStarLoop(GenericAutomaton a) {
	State s = new State(DefaultTokenType.ACCEPT);
	State next = a.getStart();
	s.addTransition(new EpsilonTransition(next));
	for (State p : next.findAcceptStates()) {
		p.addTransition(new EpsilonTransition(s));
	}
	return new GenericAutomaton(s);
} public static GenericAutomaton matchUnlimitedLoop(GenericAutomaton a, int start) {
	if (start == 0) {
		return matchStarLoop(a);
	} else {
		GenericAutomaton[] as = copyOf(a, new GenericAutomaton[start + 1], start);
		as[start] = matchStarLoop(a.clone());
		return matchConcatenation(as);
	}
} public static DotGraphMatcher startsWith(String prefix) {
	return new DotGraphMatcher().startingWith(prefix);
} public interface TokenType {

	boolean error();
	boolean accept();

} static class State implements Cloneable {

	private TokenType type;
	private List<Transition> transitions;

	public State() {
		this.transitions = new ArrayList<Transition>();
	}

	public State(TokenType type) {
		this.type = type;
		this.transitions = new ArrayList<Transition>();
	}

	public boolean accept() {
		return type != null && type.accept();
	}

	public boolean error() {
		return type != null && type.error();
	}

	public String getId() {
		return String.valueOf(System.identityHashCode(this));
	}

	void setType(TokenType type) {
		this.type = type;
	}

	public TokenType getType() {
		return type;
	}

	public void addTransition(Transition transition) {
		this.transitions.add(transition);
	}

	public List<Transition> getTransitions() {
		return transitions;
	}

	public SortedSet<Character> getRelevantCharacters() {
		SortedSet<Character> relevant = new TreeSet<Character>();
		relevant.add(Character.MIN_VALUE);
		for (Transition transition : transitions) {
			char from = transition.getFrom();
			relevant.add(from);

			char to = transition.getTo();
			if (to < Character.MAX_VALUE) {
				relevant.add(after(to));
			}
		}
		return relevant;
	}

	public Set<State> getDirectlyReachableStates() {
		Set<State> reachable = new LinkedHashSet<State>();
		for (Transition transition : transitions) {
			reachable.add(transition.getTarget());
		}
		return reachable;
	}

	public State next(char ch) {
		for (Transition transition : transitions) {
			if (transition.matches(ch)) {
				return transition.getTarget();
			}
		}
		return null;
	}

	void mergeAdjacentTransitions() {
		SortedSet<Transition> sortedTransitions = computeSortedTransitions();
		LinkedList<Transition> mergedTransitions = new LinkedList<Transition>();

		for (Transition transition : sortedTransitions) {
			if (mergedTransitions.isEmpty()) {
				mergedTransitions.add(transition);
			} else {
				Transition last = mergedTransitions.getLast();
				char lastFrom = last.getFrom();
				char lastTo = last.getTo();
				char nextFrom = transition.getFrom();
				char nextTo = transition.getTo();
				if (lastTo + 1 >= nextFrom && last.getTarget() == transition.getTarget()) {
					mergedTransitions.removeLast();
					char from = lastFrom < nextFrom ? lastFrom : nextFrom;
					char to = lastTo < nextTo ? nextTo : lastTo;
					mergedTransitions.add(new RangeTransition(from, to, last.getTarget()));
				} else {
					mergedTransitions.add(transition);
				}
			}
		}
		this.transitions = new ArrayList<Transition>(mergedTransitions);
	}

	@Override
	public State clone() {
		try {
			State clone = (State) super.clone();
			clone.type = type;
			clone.transitions = new ArrayList<Transition>(transitions.size());
			return clone;
		} catch (CloneNotSupportedException e) {
			return null;
		}
	}

	public com.almondtools.rexlex.automaton.GenericAutomaton.State toNFA() {
		com.almondtools.rexlex.automaton.GenericAutomaton.State nfastate = new com.almondtools.rexlex.automaton.GenericAutomaton.State();
		nfastate.setType(type);
		return nfastate;
	}

	public <T> T apply(StateVisitor<T> visitor) {
		return visitor.visitState(this);
	}

	@Override
	public String toString() {
		StringBuilder buffer = new StringBuilder("state(").append(getId()).append(")\n");
		for (Transition transition : transitions) {
			buffer.append('\t').append(transition.toString()).append('\n');
		}
		return buffer.toString();
	}

	void addErrorTransitions(State error) {
		SortedSet<Transition> sortedTransitions = computeSortedTransitions();
		char current = Character.MIN_VALUE;
		for (Transition transition : sortedTransitions) {
			char from = transition.getFrom();
			char to = transition.getTo();
			if (from == current + 1) {
				transitions.add(new ExactTransition(current, error));
			} else if (from > current) {
				transitions.add(new RangeTransition(current, before(from), error));
			}
			current = after(to);
		}
		if (current == Character.MAX_VALUE) {
			transitions.add(new ExactTransition(Character.MAX_VALUE, error));
		} else {// current < Character.MAX_VALUE
			transitions.add(new RangeTransition(current, Character.MAX_VALUE, error));
		}
	}

	SortedSet<Transition> computeSortedTransitions() {
		SortedSet<Transition> sortedTransitions = new TreeSet<Transition>(new Comparator<Transition>() {

			@Override
			public int compare(Transition o1, Transition o2) {
				int result = o1.getFrom() - o2.getFrom();
				if (result == 0) {
					result = o1.getTo() - o2.getTo();
				}
				return result;
			}
		});
		sortedTransitions.addAll(transitions);
		return sortedTransitions;
	}

	public Set<State> findAcceptStates() {
		return apply(new FindAcceptStates());
	}

	public Set<State> findReachableStates() {
		return apply(new FindStates());
	}

	public Set<State> findLiveStates() {
		Set<State> states = findReachableStates();
		Map<State, Set<State>> map = new HashMap<State, Set<State>>();
		for (State s : states) {
			map.put(s, new HashSet<State>());
		}
		for (State s : states) {
			for (Transition transition : s.getTransitions()) {
				map.get(transition.getTarget()).add(s);
			}
		}
		Set<State> live = new HashSet<State>(findAcceptStates());
		LinkedList<State> worklist = new LinkedList<State>(live);
		while (!worklist.isEmpty()) {
			State current = worklist.removeFirst();
			for (State previous : map.get(current)) {
				if (!live.contains(previous)) {
					live.add(previous);
					worklist.add(previous);
				}
			}
		}
		return live;
	}

} public static class ToTabledAutomaton implements ToAutomaton<GenericAutomaton, TabledAutomaton> {

	private TokenType remainder;

	public ToTabledAutomaton() {
	}

	public ToTabledAutomaton(TokenType remainder) {
		this.remainder = remainder;
	}

	@Override
	public TabledAutomaton transform(GenericAutomaton automaton) {
		DeterministicAutomaton dfa = createDeterministicAutomaton(automaton);
		char[] relevantChars = CharUtils.fromWrapped(dfa.computeRelevantCharacters());
		return new TabledAutomaton(relevantChars, dfa.getStart(), dfa.getError(), dfa.getProperty());
	}

	private DeterministicAutomaton createDeterministicAutomaton(GenericAutomaton automaton) {
		GenericAutomaton almostDeterministic = automaton.clone().eliminateEpsilons().determinize();
		if (remainder != null) {
			GenericAutomaton almostMinimalDeterministic = almostDeterministic.totalizeAndClean(remainder).minimize();
			Map<com.almondtools.rexlex.automaton.GenericAutomaton.State, State> mappedStates = mapStates(almostMinimalDeterministic.findAllStates());
			return new DeterministicAutomaton(mappedStates.get(almostMinimalDeterministic.getStart()), mappedStates.get(almostMinimalDeterministic.getError()));
		} else {
			GenericAutomaton totalizeAndClean = almostDeterministic.totalizeAndClean();
			GenericAutomaton almostMinimalDeterministic = totalizeAndClean.minimize();
			Map<com.almondtools.rexlex.automaton.GenericAutomaton.State, State> mappedStates = mapStates(almostMinimalDeterministic.findAllStates());
			return new DeterministicAutomaton(mappedStates.get(almostMinimalDeterministic.getStart()), mappedStates.get(almostMinimalDeterministic.getError()));
		}
	}

} public enum DefaultTokenType implements TokenType {
	IGNORE(), // state is acceptable, but match should be ignored
	ACCEPT(), // state is acceptable, and match may be returned
	ERROR(true) // state is not acceptable and indicates an error
	;

	private boolean error;

	private DefaultTokenType() {
		this(false);
	}

	private DefaultTokenType(boolean error) {
		this.error = error;
	}

	@Override
	public boolean error() {
		return error;
	}

	@Override
	public boolean accept() {
		return !error;
	}

	public static DefaultTokenType merge(DefaultTokenType type1, DefaultTokenType type2) {
		if (type1 == null) {
			return type2;
		} else if (type2 == null) {
			return type1;
		} else if (type1.compareTo(type2) > 0) {
			return type1;
		} else {
			return type2;
		}
	}

} public class Pattern {

	private static final GenericAutomatonBuilder DEFAULT_AUTOMATON_BUILDER = new GenericAutomatonBuilder();

	private String pattern;
	private MatcherBuilder builder;

	private Pattern(String pattern, MatcherBuilder builder) {
		this.pattern = pattern;
		this.builder = builder;
	}

	private static DefaultMatcherBuilder defaultMatcherBuilder() {
		return new DefaultMatcherBuilder();
	}

	public String pattern() {
		return pattern;
	}

	public static GenericAutomaton compileGenericAutomaton(String pattern, List<PatternOption> options) {
		List<PatternFlag> patternFlags = splitOf(options, PatternFlag.class);
		RegexParserOption[] parserOptions = new RegexParserOption[patternFlags.size()];
		for (int i = 0; i < parserOptions.length; i++) {
			parserOptions[i] = patternFlags.get(i).getOption();
		}
		RegexNode node = new RegexParser(pattern, parserOptions).parse();
		RemainderTokenType tokenType = splitFirst(options, RemainderTokenType.class);
		if (tokenType == null) {
			return automatonBuilder(options).buildFrom(node);
		} else {
			return automatonBuilder(options).buildFrom(node, tokenType.getRemainder());
		}
	}

	public static GenericAutomaton compileGenericAutomaton(String pattern, PatternOption... options) {
		return compileGenericAutomaton(pattern, list(options));
	}

	public static <T extends Automaton> T compileAutomaton(String pattern, ToAutomaton<GenericAutomaton, T> transformer, List<PatternOption> list) {
		GenericAutomaton genericAutomaton = compileGenericAutomaton(pattern, list);
		return transformer.transform(genericAutomaton);
	}

	public static <T extends Automaton> T compileAutomaton(String pattern, ToAutomaton<GenericAutomaton, T> transformer, PatternOption... options) {
		return compileAutomaton(pattern, transformer, list(options));
	}

	public static Pattern compile(String pattern, List<PatternOption> options) {
		GenericAutomaton genericAutomaton = compileGenericAutomaton(pattern, options);
		return new Pattern(pattern, matcherBuilder(options).initWith(genericAutomaton));
	}

	public static Pattern compile(String pattern, PatternOption... options) {
		return compile(pattern, list(options));
	}

	private static AutomatonBuilder automatonBuilder(List<PatternOption> options) {
		AutomatonBuilder builder = splitFirst(options, AutomatonBuilder.class);
		if (builder == null) {
			return DEFAULT_AUTOMATON_BUILDER;
		}
		return builder;
	}

	private static MatcherBuilder matcherBuilder(List<PatternOption> options) {
		MatcherBuilder builder = splitFirst(options, MatcherBuilder.class);
		if (builder == null) {
			return defaultMatcherBuilder();
		}
		return builder;
	}
	
	public Finder finder(String input) {
		return builder.buildFinder(input);
	}

	public Matcher matcher(String input) {
		return builder.buildMatcher(input);
	}

} public class TestTokenFactory implements TokenFactory<TestToken>{

	@Override
	public TestToken createToken(String literal, TokenType type) {
		return new TestToken(literal, type);
	}
}
import static com.almondtools.rexlex.automaton.Automatons.assertMatches;
import static com.almondtools.rexlex.automaton.Automatons.chars;
import static com.almondtools.rexlex.automaton.Automatons.invalid1;
import static com.almondtools.rexlex.automaton.Automatons.invalid2;
import static com.almondtools.rexlex.automaton.Automatons.invalid3;
import static com.almondtools.rexlex.automaton.Automatons.invalid4;
import static com.almondtools.rexlex.automaton.Automatons.invalid5;
import static com.almondtools.rexlex.automaton.Automatons.invalid8;
import static com.almondtools.rexlex.automaton.Automatons.invalid9;
import static com.almondtools.rexlex.automaton.Automatons.matchPrefixes;
import static com.almondtools.rexlex.automaton.Automatons.matchSamples;
import static com.almondtools.rexlex.automaton.Automatons.nfa1;
import static com.almondtools.rexlex.automaton.Automatons.nfa2;
import static com.almondtools.rexlex.automaton.Automatons.nfa3;
import static com.almondtools.rexlex.automaton.Automatons.nfa4;
import static com.almondtools.rexlex.automaton.Automatons.nfa5;
import static com.almondtools.rexlex.automaton.Automatons.nfa8;
import static com.almondtools.rexlex.automaton.Automatons.nfa9;
import static com.almondtools.rexlex.automaton.Automatons.valid1;
import static com.almondtools.rexlex.automaton.Automatons.valid2;
import static com.almondtools.rexlex.automaton.Automatons.valid3;
import static com.almondtools.rexlex.automaton.Automatons.valid4;
import static com.almondtools.rexlex.automaton.Automatons.valid5;
import static com.almondtools.rexlex.automaton.Automatons.valid8;
import static com.almondtools.rexlex.automaton.Automatons.valid9;
import static com.almondtools.rexlex.automaton.Automatons.withOutEmpty;
import static com.almondtools.rexlex.automaton.Automatons.withTokens;
import static com.almondtools.rexlex.automaton.GenericAutomatonBuilder.match;
import static com.almondtools.rexlex.automaton.GenericAutomatonBuilder.matchAlternatives;
import static com.almondtools.rexlex.automaton.GenericAutomatonBuilder.matchAnyChar;
import static com.almondtools.rexlex.automaton.GenericAutomatonBuilder.matchAnyOf;
import static com.almondtools.rexlex.automaton.GenericAutomatonBuilder.matchComplement;
import static com.almondtools.rexlex.automaton.GenericAutomatonBuilder.matchConcatenation;
import static com.almondtools.rexlex.automaton.GenericAutomatonBuilder.matchConjunctive;
import static com.almondtools.rexlex.automaton.GenericAutomatonBuilder.matchEmpty;
import static com.almondtools.rexlex.automaton.GenericAutomatonBuilder.matchFixedLoop;
import static com.almondtools.rexlex.automaton.GenericAutomatonBuilder.matchNothing;
import static com.almondtools.rexlex.automaton.GenericAutomatonBuilder.matchOptional;
import static com.almondtools.rexlex.automaton.GenericAutomatonBuilder.matchRangeLoop;
import static com.almondtools.rexlex.automaton.GenericAutomatonBuilder.matchStarLoop;
import static com.almondtools.rexlex.automaton.GenericAutomatonBuilder.matchUnlimitedLoop;
import static com.almondtools.rexlex.pattern.DefaultTokenType.ACCEPT;
import static com.almondtools.rexlex.pattern.DotGraphMatcher.startsWith;
import static com.almondtools.rexlex.tokens.Accept.A;
import static com.almondtools.rexlex.tokens.Accept.B;
import static com.almondtools.rexlex.tokens.Fail.TESTERROR;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.empty;
import static org.junit.Assert.assertThat;
import java.io.ByteArrayOutputStream;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import com.almondtools.rexlex.TokenType;
import com.almondtools.rexlex.automaton.DeterministicAutomaton.State;
import com.almondtools.rexlex.automaton.FromGenericAutomaton.ToTabledAutomaton;
import com.almondtools.rexlex.pattern.DefaultTokenType;
import com.almondtools.rexlex.pattern.Pattern;
import com.almondtools.rexlex.tokens.TestTokenFactory;
import net.amygdalum.util.text.CharUtils;
package com.almondtools.rexlex.automaton;





public class TabledAutomatonTest {

	private static final int START = 0;
	private static final int ERROR = 1;

	private TestTokenFactory factory;

	@Before
	public void before() {
		this.factory = new TestTokenFactory();
	}

	@Test
	public void testFindPathToStartState() throws Exception {
		TabledAutomaton a = match('a').toAutomaton(new ToTabledAutomaton());