private Type doParse(String input) {
      final Deque<Term> terms = new LinkedList<>();

      for (Term t : Code.termsFrom(input)) {
        if (!t.isWhitespace())
          terms.add(t);
      }

      class Reader {

        Type type() {
          Term t = terms.peek();
          if (t.isWordOrNumber()) {
            Type type = named();

            t = terms.peek();
            if (t != null) {
              if (t.is("<")) {
                type = arguments(type);
              }
              while (!terms.isEmpty()) {
                t = terms.peek();
                if (t.is("[")) {
                  type = array(type);
                } else {
                  break;
                }
              }
              if (t.is(".")) {
                type = varargs(type);
              }
            }
            return type;
          } else if (t.is("@")) {
            // just consume type annotation
            terms.poll();
            consumeAnnotation();
            // and try again, yep, recursively...
            return type();
          } else if (t.is("(")) {
            Type type = annotatedType();
            while (!terms.isEmpty()) {
              t = terms.peek();
              if (t.is("[")) {
                type = array(type);
              } else {
                break;
              }
            }
            return type;
          }
          throw new IllegalStateException("unexpected term '" + t + "'");
        }

        Type annotatedType() {
          terms.poll();
          consumeAnnotation();
          expect(terms.poll(), ":");
          expect(terms.poll(), ":");
          Type type = type();
          expect(terms.poll(), ")");
          return type;
        }

        Wildcard wildcard() {
          expect(terms.poll(), "?");

          Term t = terms.peek();
          if (t.is("super")) {
            terms.poll();
            Defined lowerBound = (Defined) type();
            return factory.superWildcard(lowerBound);
          }
          if (t.is("extends")) {
            terms.poll();
            Defined upperBound = (Defined) type();
            return factory.extendsWildcard(upperBound);
          }
          return factory.extendsWildcard(OBJECT);
        }

        Type array(Type element) {
          expect(terms.poll(), "[");
          expect(terms.poll(), "]");
          return factory.array(element);
        }

        Type varargs(Type element) {
          expect(terms.poll(), ".");
          expect(terms.poll(), ".");
          expect(terms.poll(), ".");
          return factory.varargs(element);
        }

        Type arguments(Type reference) {
          expect(terms.poll(), "<");

          List<Nonprimitive> arguments = new ArrayList<>();
          for (;;) {
            if (terms.peek().is("?")) {
              arguments.add(wildcard());
            } else {
              arguments.add((Nonprimitive) type());
            }
            if (!terms.isEmpty() && terms.peek().is(",")) {
              terms.poll();
            } else
              break;
          }

          expect(terms.poll(), ">");

          return factory.parameterized((Reference) reference, arguments);
        }

        Type named() {
          List<String> segments = new ArrayList<>();

          for (;;) {
            if (terms.peek().isWordOrNumber()) {
              segments.add(terms.poll().toString());
            } else if (terms.peek().is("@")) {
              terms.poll();
              // just consume type annotation
              consumeAnnotation();
              continue;
            } else {
              break;
            }

            if (!terms.isEmpty() && terms.peek().is(".")) {
              if (terms.size() >= 2) {
                // case when varargs may be so more than one dot
                // but we handle rest of it elsewhere
                Iterator<Term> it = terms.iterator();
                if (it.next().is(".") && it.next().is(".")) {
                  break;
                }
              }
              terms.poll();
            } else {
              break;
            }
          }

          return forName(JOINER.join(segments));
        }

        private void consumeAnnotation() {
          named();
          consumeAnnotationParameters();
          consumeErraticTrailingComma();
        }

        private void consumeAnnotationParameters() {
          consumeRecursiveUntil("(", ")");
        }
        
        private void consumeRecursiveUntil(String begin, String end) {
          if (!terms.isEmpty() && terms.peek().is(begin)) {
            terms.poll();
            while(!terms.isEmpty()) {
              Term t = terms.peek();
              if (t.is(end)) {
                terms.poll();
                return;
              }
              if (t.is(begin)) {
                consumeRecursiveUntil(begin, end);
              } else {
                terms.poll();
              }
            }
          }
        }

        private void consumeErraticTrailingComma() {
          if (!terms.isEmpty() && terms.peek().is(",")) {
            terms.poll();
          }
        }

        void expect(Term t, String is) {
          if (t == null || !t.is(is)) {
            throw new IllegalStateException("expected '" + is + "' but got '" + t + "'");
          }
        }
      }

      Type type = new Reader().type();

      if (!terms.isEmpty()) {
        throw new IllegalStateException("unexpected trailing terms '" + Joiner.on("").join(terms) + "'");
      }

      return type;
    }
I've created this type model as an experiment which I want to bring forward and evolve
into something more general purpose, probably, an utility library some day.
The idea here is to give practical, yet accurate depiction of the type system in java using
immutable types, being lightweight, efficient and easy to analyse and transform. Apparently,
neither {@code java.lang.reflect} nor {@code javax.lang.model} (nor any 3rd party lib I've seen)
are not suitable for anything I want to do.
<p>
What we tried to avoid:
<ul>
<li>Compicated reverse references and mutability</li>
<li>Idealism and unrealistic overgeneralization ({@link java.lang.reflect.WildcardType}
anyone?)</li>
<li>Complicated types like intersection or unions where we get without them</li>
</ul>
Moreover we are only concerned with the types in signatures, not a whole spectre of types which
might occur in java code.
value-processor/src/org/immutables/value/processor/encode/Type.java