James,

>   3. I want to know how the library works internally.
>
> The third use-case is the only time literate programming makes sense, but
> it's also the least used of the three. I'm also not hugely convinced it's
> actually much use - whenever I read literate programs in Clojure I find
> myself skipping down to the code, as it's actually easier for me to read
> the code than the English text accompanying it!


I've attached a piece of code from Clojure, including the terse
"documentation". I presume one of the early Clojure authors wrote it
so I assume it is "best case, production code" by Java experts.

I am currently writing a literate version of Clojure and I'm trying to
explain this method. I can read the code and I've been programming in
Java since it was called Oak but I must say I still find this quite
opaque and hard to explain. I'm also familiar with the visitor pattern.

This code has low-level, semantically void operations like "v + 2"
operations on indices, similar in style to pointer operations in C.
There is flag testing (e.g. dann != 0) on variables whose names are not
exactly indicitive of the semantics. There are unexplained "options
flags" which "can be used to modify the default behavior of the class".
There is endless nested testing of conditions. If I have to add a new
attrName what contracts do I need to fulfill? What invariants must I
maintain? Should w be v+6 or anns be v+6?

This is code Clojure programmers depend on to work. Are you suggesting
that it is easier to read this code than a few paragraphs of natural
language? 

I must say I really find it puzzling that there is so much 
resistance to writing words. It's not that hard.


/**
 * Makes the given visitor visit the Java class of this 
 * {@link ClassReader}. This class is the one specified in the 
 * constructor (see {@link #ClassReader(byte[]) ClassReader}).
 *
 * @param classVisitor the visitor that must visit this class.
 * @param attrs        prototypes of the attributes that must be parsed 
 *                     during the visit of the class. Any attribute whose
 *                     type is not equal to the type of one the 
 *                     prototypes will not be parsed: its byte array
 *                     value will be passed unchanged to the ClassWriter. 
 *                     <i>This may corrupt it if this value contains 
 *                     references to the constant pool, or has syntactic 
 *                     or semantic links with a class element that has
 *                     been transformed by a class adapter between the 
 *                     reader and the writer</i>.
 * @param flags        option flags that can be used to modify the 
 *                     default behavior of this class. See 
 *                     {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES}.
 */
public void accept(
        final ClassVisitor classVisitor,
        final Attribute[] attrs,
        final int flags){
    byte[] b = this.b; // the bytecode array
    char[] c = new char[maxStringLength]; // buffer used to read strings
    int i, j, k; // loop variables
    int u, v, w; // indexes in b
    Attribute attr;

    int access;
    String name;
    String desc;
    String attrName;
    String signature;
    int anns = 0;
    int ianns = 0;
    Attribute cattrs = null;

    // visits the header
    u = header;
    access = readUnsignedShort(u);
    name = readClass(u + 2, c);
    v = items[readUnsignedShort(u + 4)];
    String superClassName = v == 0 ? null : readUTF8(v, c);
    String[] implementedItfs = new String[readUnsignedShort(u + 6)];
    w = 0;
    u += 8;
    for(i = 0; i < implementedItfs.length; ++i)
        {
        implementedItfs[i] = readClass(u, c);
        u += 2;
        }

    boolean skipCode = (flags & SKIP_CODE) != 0;
    boolean skipDebug = (flags & SKIP_DEBUG) != 0;
    boolean unzip = (flags & EXPAND_FRAMES) != 0;

    // skips fields and methods
    v = u;
    i = readUnsignedShort(v);
    v += 2;
    for(; i > 0; --i)
        {
        j = readUnsignedShort(v + 6);
        v += 8;
        for(; j > 0; --j)
            {
            v += 6 + readInt(v + 2);
            }
        }
    i = readUnsignedShort(v);
    v += 2;
    for(; i > 0; --i)
        {
        j = readUnsignedShort(v + 6);
        v += 8;
        for(; j > 0; --j)
            {
            v += 6 + readInt(v + 2);
            }
        }
    // reads the class's attributes
    signature = null;
    String sourceFile = null;
    String sourceDebug = null;
    String enclosingOwner = null;
    String enclosingName = null;
    String enclosingDesc = null;

    i = readUnsignedShort(v);
    v += 2;
    for(; i > 0; --i)
        {
        attrName = readUTF8(v, c);
        // tests are sorted in decreasing frequency order
        // (based on frequencies observed on typical classes)
        if(attrName.equals("SourceFile"))
            {
            sourceFile = readUTF8(v + 6, c);
            }
        else if(attrName.equals("InnerClasses"))
            {
            w = v + 6;
            }
        else if(attrName.equals("EnclosingMethod"))
            {
            enclosingOwner = readClass(v + 6, c);
            int item = readUnsignedShort(v + 8);
            if(item != 0)
                {
                enclosingName = readUTF8(items[item], c);
                enclosingDesc = readUTF8(items[item] + 2, c);
                }
            }
        else if(attrName.equals("Signature"))
            {
            signature = readUTF8(v + 6, c);
            }
        else if(attrName.equals("RuntimeVisibleAnnotations"))
            {
            anns = v + 6;
            }
        else if(attrName.equals("Deprecated"))
            {
            access |= Opcodes.ACC_DEPRECATED;
            }
        else if(attrName.equals("Synthetic"))
            {
            access |= Opcodes.ACC_SYNTHETIC;
            }
        else if(attrName.equals("SourceDebugExtension"))
            {
            int len = readInt(v + 2);
            sourceDebug = readUTF(v + 6, len, new char[len]);
            }
        else if(attrName.equals("RuntimeInvisibleAnnotations"))
            {
            ianns = v + 6;
            }
        else
            {
            attr = readAttribute(attrs,
                                 attrName,
                                 v + 6,
                                 readInt(v + 2),
                                 c,
                                 -1,
                                 null);
            if(attr != null)
                {
                attr.next = cattrs;
                cattrs = attr;
                }
            }
        v += 6 + readInt(v + 2);
        }
    // calls the visit method
    classVisitor.visit(readInt(4),
                       access,
                       name,
                       signature,
                       superClassName,
                       implementedItfs);

    // calls the visitSource method
    if(!skipDebug && (sourceFile != null || sourceDebug != null))
        {
        classVisitor.visitSource(sourceFile, sourceDebug);
        }

    // calls the visitOuterClass method
    if(enclosingOwner != null)
        {
        classVisitor.visitOuterClass(enclosingOwner,
                                     enclosingName,
                                     enclosingDesc);
        }

    // visits the class annotations
    for(i = 1; i >= 0; --i)
        {
        v = i == 0 ? ianns : anns;
        if(v != 0)
            {
            j = readUnsignedShort(v);
            v += 2;
            for(; j > 0; --j)
                {
                v = readAnnotationValues(v + 2, c, true,
                  classVisitor.visitAnnotation(readUTF8(v, c), i != 0));
                }
            }
        }

    // visits the class attributes
    while(cattrs != null)
        {
        attr = cattrs.next;
        cattrs.next = null;
        classVisitor.visitAttribute(cattrs);
        cattrs = attr;
        }

    // calls the visitInnerClass method
    if(w != 0)
        {
        i = readUnsignedShort(w);
        w += 2;
        for(; i > 0; --i)
            {
            classVisitor.visitInnerClass(
              readUnsignedShort(w) == 0
              ? null
              : readClass(w, c), readUnsignedShort(w + 2) == 0
                 ? null
                 : readClass(w + 2, c), readUnsignedShort(w + 4) == 0
                    ? null
                    : readUTF8(w + 4, c),
                       readUnsignedShort(w + 6));
            w += 8;
            }
        }

    // visits the fields
    i = readUnsignedShort(u);
    u += 2;
    for(; i > 0; --i)
        {
        access = readUnsignedShort(u);
        name = readUTF8(u + 2, c);
        desc = readUTF8(u + 4, c);
        // visits the field's attributes and looks for a ConstantValue
        // attribute
        int fieldValueItem = 0;
        signature = null;
        anns = 0;
        ianns = 0;
        cattrs = null;

        j = readUnsignedShort(u + 6);
        u += 8;
        for(; j > 0; --j)
            {
            attrName = readUTF8(u, c);
            // tests are sorted in decreasing frequency order
            // (based on frequencies observed on typical classes)
            if(attrName.equals("ConstantValue"))
                {
                fieldValueItem = readUnsignedShort(u + 6);
                }
            else if(attrName.equals("Signature"))
                {
                signature = readUTF8(u + 6, c);
                }
            else if(attrName.equals("Deprecated"))
                {
                access |= Opcodes.ACC_DEPRECATED;
                }
            else if(attrName.equals("Synthetic"))
                {
                access |= Opcodes.ACC_SYNTHETIC;
                }
            else if(attrName.equals("RuntimeVisibleAnnotations"))
                {
                anns = u + 6;
                }
            else if(attrName.equals("RuntimeInvisibleAnnotations"))
                {
                ianns = u + 6;
                }
            else
                {
                attr = readAttribute(attrs,
                                     attrName,
                                     u + 6,
                                     readInt(u + 2),
                                     c,
                                     -1,
                                     null);
                if(attr != null)
                    {
                    attr.next = cattrs;
                    cattrs = attr;
                    }
                }
            u += 6 + readInt(u + 2);
            }
        // visits the field
        FieldVisitor fv = 
         classVisitor.visitField(access, name, desc, signature,
           fieldValueItem == 0 ? null : readConst(fieldValueItem, c));
        // visits the field annotations and attributes
        if(fv != null)
            {
            for(j = 1; j >= 0; --j)
                {
                v = j == 0 ? ianns : anns;
                if(v != 0)
                    {
                    k = readUnsignedShort(v);
                    v += 2;
                    for(; k > 0; --k)
                        {
                        v = readAnnotationValues(v + 2, c, true,
                           fv.visitAnnotation(readUTF8(v, c), j != 0));
                        }
                    }
                }
            while(cattrs != null)
                {
                attr = cattrs.next;
                cattrs.next = null;
                fv.visitAttribute(cattrs);
                cattrs = attr;
                }
            fv.visitEnd();
            }
        }

    // visits the methods
    i = readUnsignedShort(u);
    u += 2;
    for(; i > 0; --i)
        {
        int u0 = u + 6;
        access = readUnsignedShort(u);
        name = readUTF8(u + 2, c);
        desc = readUTF8(u + 4, c);
        signature = null;
        anns = 0;
        ianns = 0;
        int dann = 0;
        int mpanns = 0;
        int impanns = 0;
        cattrs = null;
        v = 0;
        w = 0;

        // looks for Code and Exceptions attributes
        j = readUnsignedShort(u + 6);
        u += 8;
        for(; j > 0; --j)
            {
            attrName = readUTF8(u, c);
            int attrSize = readInt(u + 2);
            u += 6;
            // tests are sorted in decreasing frequency order
            // (based on frequencies observed on typical classes)
            if(attrName.equals("Code"))
                {
                if(!skipCode)
                    {
                    v = u;
                    }
                }
            else if(attrName.equals("Exceptions"))
                {
                w = u;
                }
            else if(attrName.equals("Signature"))
                {
                signature = readUTF8(u, c);
                }
            else if(attrName.equals("Deprecated"))
                {
                access |= Opcodes.ACC_DEPRECATED;
                }
            else if(attrName.equals("RuntimeVisibleAnnotations"))
                {
                anns = u;
                }
            else if(attrName.equals("AnnotationDefault"))
                {
                dann = u;
                }
            else if(attrName.equals("Synthetic"))
                {
                access |= Opcodes.ACC_SYNTHETIC;
                }
            else if(attrName.equals("RuntimeInvisibleAnnotations"))
                {
                ianns = u;
                }
            else if(attrName.equals(
                    "RuntimeVisibleParameterAnnotations"))
                {
                mpanns = u;
                }
            else if(attrName.equals(
                     "RuntimeInvisibleParameterAnnotations"))
                {
                impanns = u;
                }
            else
                {
                attr = readAttribute(attrs,
                                     attrName,
                                     u,
                                     attrSize,
                                     c,
                                     -1,
                                     null);
                if(attr != null)
                    {
                    attr.next = cattrs;
                    cattrs = attr;
                    }
                }
            u += attrSize;
            }
        // reads declared exceptions
        String[] exceptions;
        if(w == 0)
            {
            exceptions = null;
            }
        else
            {
            exceptions = new String[readUnsignedShort(w)];
            w += 2;
            for(j = 0; j < exceptions.length; ++j)
                {
                exceptions[j] = readClass(w, c);
                w += 2;
                }
            }

        // visits the method's code, if any
        MethodVisitor mv = classVisitor.visitMethod(access,
                                                    name,
                                                    desc,
                                                    signature,
                                                    exceptions);

        if(mv != null)
            {
          /*
           * if the returned MethodVisitor is in fact a MethodWriter, it
           * means there is no method adapter between the reader and the
           * writer. If, in addition, the writer's constant pool was
           * copied from this reader (mw.cw.cr == this), and the 
           * signature and exceptions of the method have not been 
           * changed, then it is possible to skip all visit events and 
           * just copy the original code of the method to the writer 
           * (the access, name and descriptor can have been changed, 
           * this is not important since they are not copied as is from 
           * the reader).
           */
            if(mv instanceof MethodWriter)
                {
                MethodWriter mw = (MethodWriter) mv;
                if(mw.cw.cr == this)
                    {
                    if(signature == mw.signature)
                        {
                        boolean sameExceptions = false;
                        if(exceptions == null)
                            {
                            sameExceptions = mw.exceptionCount == 0;
                            }
                        else
                            {
                            if(exceptions.length == mw.exceptionCount)
                            {
                             sameExceptions = true;
                             for(j = exceptions.length - 1; j >= 0; --j)
                             {
                               w -= 2;
                               if(mw.exceptions[j] != 
                                           readUnsignedShort(w))
                               {
                                 sameExceptions = false;
                                 break;
                                }
                               }
                              }
                            }
                        if(sameExceptions)
                            {
                           /*
                            * we do not copy directly the code into
                            * MethodWriter to save a byte array copy
                            * operation. The real copy will be done in
                            * ClassWriter.toByteArray().
                            */
                            mw.classReaderOffset = u0;
                            mw.classReaderLength = u - u0;
                            continue;
                            }
                        }
                    }
                }

            if(dann != 0)
                {
                AnnotationVisitor dv = mv.visitAnnotationDefault();
                readAnnotationValue(dann, c, null, dv);
                if(dv != null)
                    {
                    dv.visitEnd();
                    }
                }
            for(j = 1; j >= 0; --j)
                {
                w = j == 0 ? ianns : anns;
                if(w != 0)
                    {
                    k = readUnsignedShort(w);
                    w += 2;
                    for(; k > 0; --k)
                        {
                        w = readAnnotationValues(w + 2, c, true,
                          mv.visitAnnotation(readUTF8(w, c), j != 0));
                        }
                    }
                }
            if(mpanns != 0)
                {
                readParameterAnnotations(mpanns, c, true, mv);
                }
            if(impanns != 0)
                {
                readParameterAnnotations(impanns, c, false, mv);
                }
            while(cattrs != null)
                {
                attr = cattrs.next;
                cattrs.next = null;
                mv.visitAttribute(cattrs);
                cattrs = attr;
                }
            }

        if(mv != null && v != 0)
            {
            int maxStack = readUnsignedShort(v);
            int maxLocals = readUnsignedShort(v + 2);
            int codeLength = readInt(v + 4);
            v += 8;

            int codeStart = v;
            int codeEnd = v + codeLength;

            mv.visitCode();

            // 1st phase: finds the labels
            int label;
            Label[] labels = new Label[codeLength + 1];
            while(v < codeEnd)
                {
                int opcode = b[v] & 0xFF;
                switch(ClassWriter.TYPE[opcode])
                    {
                    case ClassWriter.NOARG_INSN:
                    case ClassWriter.IMPLVAR_INSN:
                        v += 1;
                        break;
                    case ClassWriter.LABEL_INSN:
                        label = v - codeStart + readShort(v + 1);
                        if(labels[label] == null)
                            {
                            labels[label] = new Label();
                            }
                        v += 3;
                        break;
                    case ClassWriter.LABELW_INSN:
                        label = v - codeStart + readInt(v + 1);
                        if(labels[label] == null)
                            {
                            labels[label] = new Label();
                            }
                        v += 5;
                        break;
                    case ClassWriter.WIDE_INSN:
                        opcode = b[v + 1] & 0xFF;
                        if(opcode == Opcodes.IINC)
                            {
                            v += 6;
                            }
                        else
                            {
                            v += 4;
                            }
                        break;
                    case ClassWriter.TABL_INSN:
                        // skips 0 to 3 padding bytes
                        w = v - codeStart;
                        v = v + 4 - (w & 3);
                        // reads instruction
                        label = w + readInt(v);
                        if(labels[label] == null)
                            {
                            labels[label] = new Label();
                            }
                        j = readInt(v + 8) - readInt(v + 4) + 1;
                        v += 12;
                        for(; j > 0; --j)
                            {
                            label = w + readInt(v);
                            v += 4;
                            if(labels[label] == null)
                                {
                                labels[label] = new Label();
                                }
                            }
                        break;
                    case ClassWriter.LOOK_INSN:
                        // skips 0 to 3 padding bytes
                        w = v - codeStart;
                        v = v + 4 - (w & 3);
                        // reads instruction
                        label = w + readInt(v);
                        if(labels[label] == null)
                            {
                            labels[label] = new Label();
                            }
                        j = readInt(v + 4);
                        v += 8;
                        for(; j > 0; --j)
                            {
                            label = w + readInt(v + 4);
                            v += 8;
                            if(labels[label] == null)
                                {
                                labels[label] = new Label();
                                }
                            }
                        break;
                    case ClassWriter.VAR_INSN:
                    case ClassWriter.SBYTE_INSN:
                    case ClassWriter.LDC_INSN:
                        v += 2;
                        break;
                    case ClassWriter.SHORT_INSN:
                    case ClassWriter.LDCW_INSN:
                    case ClassWriter.FIELDORMETH_INSN:
                    case ClassWriter.TYPE_INSN:
                    case ClassWriter.IINC_INSN:
                        v += 3;
                        break;
                    case ClassWriter.ITFMETH_INSN:
                        v += 5;
                        break;
                        // case MANA_INSN:
                    default:
                        v += 4;
                        break;
                    }
                }
            // parses the try catch entries
            j = readUnsignedShort(v);
            v += 2;
            for(; j > 0; --j)
                {
                label = readUnsignedShort(v);
                Label start = labels[label];
                if(start == null)
                    {
                    labels[label] = start = new Label();
                    }
                label = readUnsignedShort(v + 2);
                Label end = labels[label];
                if(end == null)
                    {
                    labels[label] = end = new Label();
                    }
                label = readUnsignedShort(v + 4);
                Label handler = labels[label];
                if(handler == null)
                    {
                    labels[label] = handler = new Label();
                    }
                int type = readUnsignedShort(v + 6);
                if(type == 0)
                    {
                    mv.visitTryCatchBlock(start, end, handler, null);
                    }
                else
                    {
                    mv.visitTryCatchBlock(start,
                                          end,
                                          handler,
                                          readUTF8(items[type], c));
                    }
                v += 8;
                }
            // parses the local variable, line number tables, and code
            // attributes
            int varTable = 0;
            int varTypeTable = 0;
            int stackMap = 0;
            int frameCount = 0;
            int frameMode = 0;
            int frameOffset = 0;
            int frameLocalCount = 0;
            int frameLocalDiff = 0;
            int frameStackCount = 0;
            Object[] frameLocal = null;
            Object[] frameStack = null;
            boolean zip = true;
            cattrs = null;
            j = readUnsignedShort(v);
            v += 2;
            for(; j > 0; --j)
                {
                attrName = readUTF8(v, c);
                if(attrName.equals("LocalVariableTable"))
                    {
                    if(!skipDebug)
                        {
                        varTable = v + 6;
                        k = readUnsignedShort(v + 6);
                        w = v + 8;
                        for(; k > 0; --k)
                            {
                            label = readUnsignedShort(w);
                            if(labels[label] == null)
                                {
                                labels[label] = new Label(true);
                                }
                            label += readUnsignedShort(w + 2);
                            if(labels[label] == null)
                                {
                                labels[label] = new Label(true);
                                }
                            w += 10;
                            }
                        }
                    }
                else if(attrName.equals("LocalVariableTypeTable"))
                    {
                    varTypeTable = v + 6;
                    }
                else if(attrName.equals("LineNumberTable"))
                    {
                    if(!skipDebug)
                        {
                        k = readUnsignedShort(v + 6);
                        w = v + 8;
                        for(; k > 0; --k)
                            {
                            label = readUnsignedShort(w);
                            if(labels[label] == null)
                                {
                                labels[label] = new Label(true);
                                }
                            labels[label].line=readUnsignedShort(w + 2);
                            w += 4;
                            }
                        }
                    }
                else if(attrName.equals("StackMapTable"))
                    {
                    if((flags & SKIP_FRAMES) == 0)
                        {
                        stackMap = v + 8;
                        frameCount = readUnsignedShort(v + 6);
                        }
        /*
         * here we do not extract the labels corresponding to
         * the attribute content. This would require a full
         * parsing of the attribute, which would need to be
         * repeated in the second phase (see below). Instead the
         * content of the attribute is read one frame at a time
         * (i.e. after a frame has been visited, the next frame
         * is read), and the labels it contains are also
         * extracted one frame at a time. Thanks to the ordering
         * of frames, having only a "one frame lookahead" is not
         * a problem, i.e. it is not possible to see an offset
         * smaller than the offset of the current insn and for
         * which no Label exist.
         */
                    // TODO true for frame offsets,
                    // but for UNINITIALIZED type offsets?
                    }
                else if(attrName.equals("StackMap"))
                    {
                    if((flags & SKIP_FRAMES) == 0)
                        {
                        stackMap = v + 8;
                        frameCount = readUnsignedShort(v + 6);
                        zip = false;
                        }
                    /*
                     * IMPORTANT! here we assume that the frames are
                     * ordered, as in the StackMapTable attribute, 
                     * although this is not guaranteed by the 
                     * attribute format.
                     */
                    }
                else
                    {
                    for(k = 0; k < attrs.length; ++k)
                        {
                        if(attrs[k].type.equals(attrName))
                            {
                            attr = attrs[k].read(this,
                                                 v + 6,
                                                 readInt(v + 2),
                                                 c,
                                                 codeStart - 8,
                                                 labels);
                            if(attr != null)
                                {
                                attr.next = cattrs;
                                cattrs = attr;
                                }
                            }
                        }
                    }
                v += 6 + readInt(v + 2);
                }

            // 2nd phase: visits each instruction
            if(stackMap != 0)
                {
                // creates the very first (implicit) frame from the 
                // method descriptor
                frameLocal = new Object[maxLocals];
                frameStack = new Object[maxStack];
                if(unzip)
                    {
                    int local = 0;
                    if((access & Opcodes.ACC_STATIC) == 0)
                    {
                     if(name.equals("<init>"))
                      {
                      frameLocal[local++] = Opcodes.UNINITIALIZED_THIS;
                      }
                     else
                      {
                      frameLocal[local++] = readClass(header + 2, c);
                      }
                    }
                    j = 1;
                    loop:
                    while(true)
                        {
                        k = j;
                        switch(desc.charAt(j++))
                            {
                            case'Z':
                            case'C':
                            case'B':
                            case'S':
                            case'I':
                                frameLocal[local++] = Opcodes.INTEGER;
                                break;
                            case'F':
                                frameLocal[local++] = Opcodes.FLOAT;
                                break;
                            case'J':
                                frameLocal[local++] = Opcodes.LONG;
                                break;
                            case'D':
                                frameLocal[local++] = Opcodes.DOUBLE;
                                break;
                            case'[':
                                while(desc.charAt(j) == '[')
                                    {
                                    ++j;
                                    }
                                if(desc.charAt(j) == 'L')
                                    {
                                    ++j;
                                    while(desc.charAt(j) != ';')
                                        {
                                        ++j;
                                        }
                                    }
                                frameLocal[local++] = 
                                    desc.substring(k, ++j);
                                break;
                            case'L':
                                while(desc.charAt(j) != ';')
                                    {
                                    ++j;
                                    }
                                frameLocal[local++] = 
                                    desc.substring(k + 1, j++);
                                break;
                            default:
                                break loop;
                            }
                        }
                    frameLocalCount = local;
                    }
                /*
                 * for the first explicit frame the offset is not
                 * offset_delta + 1 but only offset_delta; setting the
                 * implicit frame offset to -1 allow the use of the
                 * "offset_delta + 1" rule in all cases
                 */
                frameOffset = -1;
                }
            v = codeStart;
            Label l;
            while(v < codeEnd)
                {
                w = v - codeStart;

                l = labels[w];
                if(l != null)
                    {
                    mv.visitLabel(l);
                    if(!skipDebug && l.line > 0)
                        {
                        mv.visitLineNumber(l.line, l);
                        }
                    }

                while(frameLocal != null
                      && (frameOffset == w || frameOffset == -1))
                    {
                    // if there is a frame for this offset,
                    // makes the visitor visit it,
                    // and reads the next frame if there is one.
                    if(!zip || unzip)
                        {
                        mv.visitFrame(Opcodes.F_NEW,
                                      frameLocalCount,
                                      frameLocal,
                                      frameStackCount,
                                      frameStack);
                        }
                    else if(frameOffset != -1)
                        {
                        mv.visitFrame(frameMode,
                                      frameLocalDiff,
                                      frameLocal,
                                      frameStackCount,
                                      frameStack);
                        }

                    if(frameCount > 0)
                        {
                        int tag, delta, n;
                        if(zip)
                            {
                            tag = b[stackMap++] & 0xFF;
                            }
                        else
                            {
                            tag = MethodWriter.FULL_FRAME;
                            frameOffset = -1;
                            }
                        frameLocalDiff = 0;
                        if(tag < 
                            MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME)
                            {
                            delta = tag;
                            frameMode = Opcodes.F_SAME;
                            frameStackCount = 0;
                            }
                        else if(tag < MethodWriter.RESERVED)
                            {
                            delta = tag
                         - MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME;
                            stackMap = readFrameType(frameStack,
                                                     0,
                                                     stackMap,
                                                     c,
                                                     labels);
                            frameMode = Opcodes.F_SAME1;
                            frameStackCount = 1;
                            }
                        else
                            {
                            delta = readUnsignedShort(stackMap);
                            stackMap += 2;
                            if(tag == 
                    MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED)
                                {
                                stackMap = readFrameType(frameStack,
                                                         0,
                                                         stackMap,
                                                         c,
                                                         labels);
                                frameMode = Opcodes.F_SAME1;
                                frameStackCount = 1;
                                }
                            else if(tag >= MethodWriter.CHOP_FRAME && 
                                  tag < MethodWriter.SAME_FRAME_EXTENDED)
                                {
                                frameMode = Opcodes.F_CHOP;
                                frameLocalDiff = 
                                   MethodWriter.SAME_FRAME_EXTENDED
                                                 - tag;
                                frameLocalCount -= frameLocalDiff;
                                frameStackCount = 0;
                                }
                            else if(tag == 
                                    MethodWriter.SAME_FRAME_EXTENDED)
                                {
                                frameMode = Opcodes.F_SAME;
                                frameStackCount = 0;
                                }
                            else if(tag < MethodWriter.FULL_FRAME)
                                {
                                j = unzip ? frameLocalCount : 0;
                                for(k = tag
                                      - MethodWriter.SAME_FRAME_EXTENDED; 
                                     k > 0; k--)
                                    {
                                    stackMap = readFrameType(frameLocal,
                                                             j++,
                                                             stackMap,
                                                             c,
                                                             labels);
                                    }
                                frameMode = Opcodes.F_APPEND;
                                frameLocalDiff = tag
                                   - MethodWriter.SAME_FRAME_EXTENDED;
                                frameLocalCount += frameLocalDiff;
                                frameStackCount = 0;
                                }
                            else
                                { // if (tag == FULL_FRAME) {
                                frameMode = Opcodes.F_FULL;
                                n = frameLocalDiff 
                                  = frameLocalCount 
                                  = readUnsignedShort(stackMap);
                                stackMap += 2;
                                for(j = 0; n > 0; n--)
                                    {
                                    stackMap = readFrameType(frameLocal,
                                                             j++,
                                                             stackMap,
                                                             c,
                                                             labels);
                                    }
                                n = frameStackCount 
                                  = readUnsignedShort(stackMap);
                                stackMap += 2;
                                for(j = 0; n > 0; n--)
                                    {
                                    stackMap = readFrameType(frameStack,
                                                             j++,
                                                             stackMap,
                                                             c,
                                                             labels);
                                    }
                                }
                            }
                        frameOffset += delta + 1;
                        if(labels[frameOffset] == null)
                            {
                            labels[frameOffset] = new Label();
                            }

                        --frameCount;
                        }
                    else
                        {
                        frameLocal = null;
                        }
                    }

                int opcode = b[v] & 0xFF;
                switch(ClassWriter.TYPE[opcode])
                    {
                    case ClassWriter.NOARG_INSN:
                        mv.visitInsn(opcode);
                        v += 1;
                        break;
                    case ClassWriter.IMPLVAR_INSN:
                        if(opcode > Opcodes.ISTORE)
                            {
                            opcode -= 59; // ISTORE_0
                            mv.visitVarInsn(
                              Opcodes.ISTORE + (opcode >> 2), 
                              opcode & 0x3);
                            }
                        else
                            {
                            opcode -= 26; // ILOAD_0
                            mv.visitVarInsn(
                              Opcodes.ILOAD + (opcode >> 2),
                              opcode & 0x3);
                            }
                        v += 1;
                        break;
                    case ClassWriter.LABEL_INSN:
                        mv.visitJumpInsn(opcode, 
                                         labels[w + readShort(v + 1)]);
                        v += 3;
                        break;
                    case ClassWriter.LABELW_INSN:
                        mv.visitJumpInsn(opcode - 33, 
                                         labels[w + readInt(v + 1)]);
                        v += 5;
                        break;
                    case ClassWriter.WIDE_INSN:
                        opcode = b[v + 1] & 0xFF;
                        if(opcode == Opcodes.IINC)
                            {
                            mv.visitIincInsn(readUnsignedShort(v + 2),
                                             readShort(v + 4));
                            v += 6;
                            }
                        else
                            {
                            mv.visitVarInsn(opcode,
                                            readUnsignedShort(v + 2));
                            v += 4;
                            }
                        break;
                    case ClassWriter.TABL_INSN:
                        // skips 0 to 3 padding bytes
                        v = v + 4 - (w & 3);
                        // reads instruction
                        label = w + readInt(v);
                        int min = readInt(v + 4);
                        int max = readInt(v + 8);
                        v += 12;
                        Label[] table = new Label[max - min + 1];
                        for(j = 0; j < table.length; ++j)
                            {
                            table[j] = labels[w + readInt(v)];
                            v += 4;
                            }
                        mv.visitTableSwitchInsn(min,
                                                max,
                                                labels[label],
                                                table);
                        break;
                    case ClassWriter.LOOK_INSN:
                        // skips 0 to 3 padding bytes
                        v = v + 4 - (w & 3);
                        // reads instruction
                        label = w + readInt(v);
                        j = readInt(v + 4);
                        v += 8;
                        int[] keys = new int[j];
                        Label[] values = new Label[j];
                        for(j = 0; j < keys.length; ++j)
                            {
                            keys[j] = readInt(v);
                            values[j] = labels[w + readInt(v + 4)];
                            v += 8;
                            }
                        mv.visitLookupSwitchInsn(labels[label],
                                                 keys,
                                                 values);
                        break;
                    case ClassWriter.VAR_INSN:
                        mv.visitVarInsn(opcode, b[v + 1] & 0xFF);
                        v += 2;
                        break;
                    case ClassWriter.SBYTE_INSN:
                        mv.visitIntInsn(opcode, b[v + 1]);
                        v += 2;
                        break;
                    case ClassWriter.SHORT_INSN:
                        mv.visitIntInsn(opcode, readShort(v + 1));
                        v += 3;
                        break;
                    case ClassWriter.LDC_INSN:
                        mv.visitLdcInsn(readConst(b[v + 1] & 0xFF, c));
                        v += 2;
                        break;
                    case ClassWriter.LDCW_INSN:
                        mv.visitLdcInsn(
                          readConst(readUnsignedShort(v + 1), c));
                        v += 3;
                        break;
                    case ClassWriter.FIELDORMETH_INSN:
                    case ClassWriter.ITFMETH_INSN:
                        int cpIndex = items[readUnsignedShort(v + 1)];
                        String iowner = readClass(cpIndex, c);
                        cpIndex = items[readUnsignedShort(cpIndex + 2)];
                        String iname = readUTF8(cpIndex, c);
                        String idesc = readUTF8(cpIndex + 2, c);
                        if(opcode < Opcodes.INVOKEVIRTUAL)
                        {
                         mv.visitFieldInsn(opcode,iowner,iname,idesc);
                        }
                        else
                        {
                         mv.visitMethodInsn(opcode,iowner,iname,idesc);
                        }
                        if(opcode == Opcodes.INVOKEINTERFACE)
                            {
                            v += 5;
                            }
                        else
                            {
                            v += 3;
                            }
                        break;
                    case ClassWriter.TYPE_INSN:
                        mv.visitTypeInsn(opcode, readClass(v + 1, c));
                        v += 3;
                        break;
                    case ClassWriter.IINC_INSN:
                        mv.visitIincInsn(b[v + 1] & 0xFF, b[v + 2]);
                        v += 3;
                        break;
                        // case MANA_INSN:
                    default:
                        mv.visitMultiANewArrayInsn(readClass(v + 1, c),
                                                   b[v + 3] & 0xFF);
                        v += 4;
                        break;
                    }
                }
            l = labels[codeEnd - codeStart];
            if(l != null)
                {
                mv.visitLabel(l);
                }
            // visits the local variable tables
            if(!skipDebug && varTable != 0)
                {
                int[] typeTable = null;
                if(varTypeTable != 0)
                    {
                    k = readUnsignedShort(varTypeTable) * 3;
                    w = varTypeTable + 2;
                    typeTable = new int[k];
                    while(k > 0)
                        {
                        typeTable[--k]= w + 6; // signature
                        typeTable[--k]= readUnsignedShort(w + 8); //index
                        typeTable[--k]= readUnsignedShort(w); // start
                        w += 10;
                        }
                    }
                k = readUnsignedShort(varTable);
                w = varTable + 2;
                for(; k > 0; --k)
                    {
                    int start = readUnsignedShort(w);
                    int length = readUnsignedShort(w + 2);
                    int index = readUnsignedShort(w + 8);
                    String vsignature = null;
                    if(typeTable != null)
                        {
                        for(int a = 0; a < typeTable.length; a += 3)
                        {
                            if(typeTable[a] == start
                               && typeTable[a + 1] == index)
                            {
                             vsignature=readUTF8(typeTable[a + 2], c);
                             break;
                            }
                          }
                        }
                    mv.visitLocalVariable(readUTF8(w + 4, c),
                                          readUTF8(w + 6, c),
                                          vsignature,
                                          labels[start],
                                          labels[start + length],
                                          index);
                    w += 10;
                    }
                }
            // visits the other attributes
            while(cattrs != null)
                {
                attr = cattrs.next;
                cattrs.next = null;
                mv.visitAttribute(cattrs);
                cattrs = attr;
                }
            // visits the max stack and max locals values
            mv.visitMaxs(maxStack, maxLocals);
            }

        if(mv != null)
            {
            mv.visitEnd();
            }
        }

    // visits the end of the class
    classVisitor.visitEnd();
}

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to