@NotNull
 @Override
 public Pair<R, State> parse(@NotNull List<Token<T>> tokens, @NotNull State state)
     throws ParserException {
   if (myKey != state.getKey()) {
     myKey = state.getKey();
     myCache.clear();
   }
   final SoftReference<Pair<R, State>> ref = myCache.get(state.getPos());
   final Pair<R, State> cached = SoftReference.dereference(ref);
   if (cached != null) {
     return cached;
   }
   final Pair<R, State> result = myParser.parse(tokens, state);
   myCache.put(state.getPos(), new SoftReference<Pair<R, State>>(result));
   return result;
 }
 @NotNull
 @Override
 public Pair<R, State> parse(@NotNull List<Token<T>> tokens, @NotNull State state)
     throws ParserException {
   try {
     return myFirst.parse(tokens, state);
   } catch (ParserException e) {
     return mySecond.parse(tokens, new State(state, state.getPos(), e.getState().getMax()));
   }
 }
 @NotNull
 @Override
 public Pair<Object, State> parse(@NotNull List<Token<T>> tokens, @NotNull State state)
     throws ParserException {
   final int pos = state.getPos();
   if (pos >= tokens.size()) {
     return Pair.create(null, state);
   }
   throw new ParserException(
       String.format("Expected end of input, found %s", tokens.get(pos)), state);
 }
 @NotNull
 @Override
 public Pair<List<R>, State> parse(@NotNull List<Token<T>> tokens, @NotNull State state)
     throws ParserException {
   final List<R> list = new ArrayList<R>();
   try {
     //noinspection InfiniteLoopStatement
     while (true) {
       final Pair<R, State> result = myParser.parse(tokens, state);
       state = result.getSecond();
       list.add(result.getFirst());
     }
   } catch (ParserException e) {
     return Pair.create(list, new State(state, state.getPos(), e.getState().getMax()));
   }
 }
 @NotNull
 @Override
 public Pair<Token<T>, State> parse(@NotNull List<Token<T>> tokens, @NotNull State state)
     throws ParserException {
   final int pos = state.getPos();
   if (pos >= tokens.size()) {
     throw new ParserException("No tokens left", state);
   }
   final Token<T> token = tokens.get(pos);
   if (token.getType().equals(myType) && (myText == null || token.getText().equals(myText))) {
     final int newPos = pos + 1;
     final State newState = new State(state, newPos, Math.max(newPos, state.getMax()));
     return Pair.create(token, newState);
   }
   final String expected =
       myText != null
           ? String.format("Token(<%s>, \"%s\")", myType, myText)
           : String.format("Token(<%s>)", myType);
   throw new ParserException(String.format("Expected %s, found %s", expected, token), state);
 }