CollectionCompiler.java

package com.mackenziehigh.autumn.lang.compiler.compilers;

import com.mackenziehigh.autumn.resources.Finished;
import java.util.LinkedList;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.InsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.TypeInsnNode;

/**
 * This class generates bytecode that creates a linked-list with predefined elements.
 *
 * @author Mackenzie High
 */
@Finished("2014/07/12")
abstract class CollectionCompiler<T>
{
    /**
     * This method is invoked in order to compile an element in the list.
     * This method must add bytecode, which produces the element's value, to the code().
     * The element must be an object reference.
     * In other words, this method must auto-box the element, if needed.
     *
     * @param element is the element to compile.
     */
    public abstract void compile(T element);

    /**
     * This method provides the list that stores the generated bytecode.
     *
     * @return the aforedescribed list.
     */
    public abstract InsnList code();

    /**
     * This method returns the class representation of the collection type.
     *
     * @return the type of collection be created.
     */
    public Class type()
    {
        return LinkedList.class;
    }

    /**
     * This method generates bytecode that executes the elements of a given list
     * and then adds the results of the executions to a newly created linked list.
     *
     * <p>
     * After the bytecode is executed, a new linked-list is the top-element of the operand-stack.
     * </p>
     *
     * @param elements are the elements to of the new list to generate bytecode for.
     */
    public final void compile(final Iterable<T> elements)
    {
        final String type = Type.getInternalName(type());

        // -----------------------------------------------------------------------------------------
        // Precondition of the Operand-Stack: .....
        // -----------------------------------------------------------------------------------------

        // -----------------------------------------------------------------------------------------
        // Postcondition of the Operand-Stack: [collection]
        //                                     .....
        // -----------------------------------------------------------------------------------------
        code().add(new TypeInsnNode(Opcodes.NEW, type));

        // -----------------------------------------------------------------------------------------
        // Postcondition of the Operand-Stack: [collection]
        //                                     [collection]
        //                                     .....
        // -----------------------------------------------------------------------------------------
        code().add(new InsnNode(Opcodes.DUP));

        // -----------------------------------------------------------------------------------------
        // Postcondition of the Operand-Stack: [collection]
        //                                     .....
        // -----------------------------------------------------------------------------------------
        code().add(new MethodInsnNode(Opcodes.INVOKESPECIAL, type, "<init>", "()V"));

        // Compile each element.
        for (T element : elements)
        {
            // -------------------------------------------------------------------------------------
            // Postcondition of the Operand-Stack: [collection]
            //                                     [collection]
            //                                     .....
            // -------------------------------------------------------------------------------------
            code().add(new InsnNode(Opcodes.DUP));

            // -------------------------------------------------------------------------------------
            // Postcondition of the Operand-Stack: [element]
            //                                     [collection]
            //                                     [collection]
            //                                     .....
            // -------------------------------------------------------------------------------------
            compile(element);

            // -------------------------------------------------------------------------------------
            // Postcondition of the Operand-Stack: [boolean]
            //                                     [collection]
            //                                     .....
            // -------------------------------------------------------------------------------------
            code().add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, type, "add", "(Ljava/lang/Object;)Z"));

            // -------------------------------------------------------------------------------------
            // Postcondition of the Operand-Stack: [collection]
            //                                     .....
            // -------------------------------------------------------------------------------------
            code().add(new InsnNode(Opcodes.POP));
        }

        // -----------------------------------------------------------------------------------------
        // Condition of the Operand-Stack: [collection]
        //                                 .....
        // -----------------------------------------------------------------------------------------
    }
}