public <T> T parseClass(ClassAccessor<T> clazz, TokenStream stream) {
        debug("Entering type " + clazz.getName() + " \"" + stream.getBuffer() + "\"");
        if (!clazz.hasAnnotation(Parsable.class))
            throw new ParseException("Cannot parse non-buildable class " + clazz.getName());
        Parsable parsable = clazz.getAnnotation(Parsable.class);
        if (parsable.resolvers().length > 0)
            return parseResolvers(parsable, clazz, stream);
        T object = clazz.getInstance();

        discardTokens(stream, parsable.ignoreCase(), parsable.prefix());

        for (String fieldName : clazz.getFieldNames()) {
            debug("Entering field " + clazz.getName() + "." + fieldName + " \"" + stream.getBuffer() + "\"");
            Symbol sym = clazz.getFieldAnnotation(fieldName, Symbol.class);
            if (sym != null) {
                if (sym.optional()) {
                    TokenStream backup = stream.clone();
                    try {
                        clazz.setField(object, fieldName, parseField(clazz.getField(fieldName), sym, stream));
                    } catch (ParseException e) {
                        stream.restoreFrom(backup);
                    }
                } else
                    clazz.setField(object, fieldName, parseField(clazz.getField(fieldName), sym, stream));
            }
        }

        discardTokens(stream, parsable.ignoreCase(), parsable.suffix());

        return object;
    }