org.hua.ast.visitors.BytecodeGeneratorASTVisitor.java Source code

Java tutorial

Introduction

Here is the source code for org.hua.ast.visitors.BytecodeGeneratorASTVisitor.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package org.hua.ast.visitors;

import java.io.DataOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.hua.Registry;
import org.hua.ast.ASTNode;
import org.hua.ast.ASTUtils;
import org.hua.ast.ASTVisitor;
import org.hua.ast.ASTVisitorException;
import org.hua.ast.AccessorExpression;
import org.hua.ast.AssignmentStatement;
import org.hua.ast.BinaryExpression;
import org.hua.ast.BreakStatement;
import org.hua.ast.ClassDefinition;
import org.hua.ast.CompUnit;
import org.hua.ast.CompoundStatement;
import org.hua.ast.ContinueStatement;
import org.hua.ast.DeclarationStatement;
import org.hua.ast.Expression;
import org.hua.ast.ExpressionList;
import org.hua.ast.ExpressionStatement;
import org.hua.ast.FFDefinition;
import org.hua.ast.FFDefinitionsList;
import org.hua.ast.FieldDefinition;
import org.hua.ast.FloatLiteralExpression;
import org.hua.ast.FunctionDefinition;
import org.hua.ast.IdentifierExpression;
import org.hua.ast.IfElseStatement;
import org.hua.ast.IfStatement;
import org.hua.ast.IntegerLiteralExpression;
import org.hua.ast.NewIdentifierExpression;
import org.hua.ast.NullExpression;
import org.hua.ast.Operator;
import org.hua.ast.ParameterDeclaration;
import org.hua.ast.ParameterList;
import org.hua.ast.ParenthesisExpression;
import org.hua.ast.ReturnStatement;
import org.hua.ast.Statement;
import org.hua.ast.StatementList;
import org.hua.ast.StringLiteralExpression;
import org.hua.ast.ThisExpression;
import org.hua.ast.TypeSpecifier;
import org.hua.ast.UnaryExpression;
import org.hua.ast.WhileStatement;
import org.hua.ast.WriteStatement;
import org.hua.symbol.LocalIndexPool;
import org.hua.symbol.SymTable;
import org.hua.symbol.SymTableEntry;
import org.hua.types.TypeUtils;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.FieldNode;
import org.objectweb.asm.tree.InsnNode;
import org.objectweb.asm.tree.JumpInsnNode;
import org.objectweb.asm.tree.LabelNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.ParameterNode;
import org.objectweb.asm.tree.TypeInsnNode;
import org.objectweb.asm.tree.VarInsnNode;
import org.objectweb.asm.util.CheckClassAdapter;
import org.objectweb.asm.util.TraceClassVisitor;

/**
 *
 * @author sssotiris22
 */
public class BytecodeGeneratorASTVisitor implements ASTVisitor {

    private ClassNode cn;
    private MethodNode mn;
    private FunctionDefinition fd;
    private boolean previousIsIdentifier = false;

    public BytecodeGeneratorASTVisitor() {
        // create class
        //        cn = new ClassNode();
        //        cn.access = Opcodes.ACC_PUBLIC;
        //        cn.version = Opcodes.V1_5;
        //        cn.name = "Assignment";
        //        cn.sourceFile = "Assignment.in";
        //        cn.superName = "java/lang/Object";

        //        // create constructor
        //        mn = new MethodNode(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
        //        mn.instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V"));
        //        mn.instructions.add(new InsnNode(Opcodes.RETURN));
        //        mn.maxLocals = 1;
        //        mn.maxStack = 1;
        //        cn.methods.add(mn);
    }

    private void backpatch(List<JumpInsnNode> list, LabelNode labelNode) {
        if (list == null) {
            return;
        }
        for (JumpInsnNode instr : list) {
            instr.label = labelNode;
        }
    }

    public ClassNode getClassNode() {
        return cn;
    }

    private void handleBooleanOperator(Expression node, Operator op, Type type) throws ASTVisitorException {
        List<JumpInsnNode> trueList = new ArrayList<JumpInsnNode>();
        System.out.println("***** handle boolean " + op);
        if (type.equals(TypeUtils.STRING_TYPE)) {
            mn.instructions.add(new InsnNode(Opcodes.SWAP));
            JumpInsnNode jmp = null;
            mn.instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/String", "equals",
                    "(Ljava/lang/Object;)Z", false));
            switch (op) {
            case EQUAL:
                jmp = new JumpInsnNode(Opcodes.IFNE, null);
                break;
            case NOT_EQUAL:
                jmp = new JumpInsnNode(Opcodes.IFEQ, null);
                break;
            default:
                ASTUtils.error(node, "Operator not supported on strings");
                break;
            }
            mn.instructions.add(jmp);
            trueList.add(jmp);
        } else if (type.equals(Type.DOUBLE_TYPE)) {

            // FIXME: add DCMPG instruction
            // FIXME: add a JumpInsnNode with null label based on the operation
            //        IFEQ, IFNE, IFGT, IFGE, IFLT, IFLE
            // FIXME: add the jmp instruction into trueList
            mn.instructions.add(new InsnNode(Opcodes.DCMPG));
            JumpInsnNode jmp = null;
            switch (op) {
            case EQUAL:
                jmp = new JumpInsnNode(Opcodes.IFEQ, null);
                mn.instructions.add(jmp);
                break;
            case NOT_EQUAL:
                jmp = new JumpInsnNode(Opcodes.IFNE, null);
                mn.instructions.add(jmp);
                break;
            case GREATER:
                jmp = new JumpInsnNode(Opcodes.IFGT, null);
                mn.instructions.add(jmp);
                break;
            case GREATER_EQUAL:
                jmp = new JumpInsnNode(Opcodes.IFGE, null);
                mn.instructions.add(jmp);
                break;
            case LESS:
                jmp = new JumpInsnNode(Opcodes.IFLT, null);
                mn.instructions.add(jmp);
                break;
            case LESS_EQUAL:
                jmp = new JumpInsnNode(Opcodes.IFLE, null);
                mn.instructions.add(jmp);
                break;
            }
            trueList.add(jmp);

        } else {
            System.out.println("here");
            JumpInsnNode jmp = null;
            switch (op) {
            case EQUAL:
                jmp = new JumpInsnNode(Opcodes.IF_ICMPEQ, null);
                mn.instructions.add(jmp);
                break;
            case NOT_EQUAL:
                jmp = new JumpInsnNode(Opcodes.IF_ICMPNE, null);
                mn.instructions.add(jmp);
                break;
            case GREATER:
                System.out.println("----- greater");
                jmp = new JumpInsnNode(Opcodes.IF_ICMPGT, null);
                mn.instructions.add(jmp);
                break;
            case GREATER_EQUAL:
                jmp = new JumpInsnNode(Opcodes.IF_ICMPGE, null);
                mn.instructions.add(jmp);
                break;
            case LESS:
                jmp = new JumpInsnNode(Opcodes.IF_ICMPLT, null);
                mn.instructions.add(jmp);
                break;
            case LESS_EQUAL:
                jmp = new JumpInsnNode(Opcodes.IF_ICMPLE, null);
                mn.instructions.add(jmp);
                break;
            default:
                ASTUtils.error(node, "Operator not supported");
                break;
            }
            trueList.add(jmp);
        }
        ASTUtils.setTrueList(node, trueList);
        List<JumpInsnNode> falseList = new ArrayList<JumpInsnNode>();
        JumpInsnNode jmp = new JumpInsnNode(Opcodes.GOTO, null);
        mn.instructions.add(jmp);
        falseList.add(jmp);
        ASTUtils.setFalseList(node, falseList);
    }

    private void handleNumberOperator(ASTNode node, Operator op, Type type) throws ASTVisitorException {
        if (op.equals(Operator.PLUS)) {

            // FIXME: IADD or DADD, etc.
            //        use type.getOpcode(Opcodes.IADD) to avoid if-then
            mn.instructions.add(new InsnNode(type.getOpcode(Opcodes.IADD)));

        } else if (op.equals(Operator.MINUS)) {

            // FIXME: ISUB or DSUB, etc.
            //        use type.getOpcode() to avoid if-then
            mn.instructions.add(new InsnNode(type.getOpcode(Opcodes.ISUB)));

        } else if (op.equals(Operator.MULTIPLY)) {

            // FIXME: IMUL or DMUL, etc.
            //        use type.getOpcode() to avoid if-then
            mn.instructions.add(new InsnNode(type.getOpcode(Opcodes.IMUL)));

        } else if (op.equals(Operator.DIVISION)) {

            // FIXME: IDIV or DDIV, etc.
            //        use type.getOpcode() to avoid if-then
            mn.instructions.add(new InsnNode(type.getOpcode(Opcodes.IDIV)));

        } else if (op.isRelational()) {
            if (type.equals(Type.DOUBLE_TYPE)) {
                mn.instructions.add(new InsnNode(Opcodes.DCMPG));
                JumpInsnNode jmp = null;
                switch (op) {
                case EQUAL:
                    jmp = new JumpInsnNode(Opcodes.IFEQ, null);
                    mn.instructions.add(jmp);
                    break;
                case NOT_EQUAL:
                    jmp = new JumpInsnNode(Opcodes.IFNE, null);
                    mn.instructions.add(jmp);
                    break;
                case GREATER:
                    jmp = new JumpInsnNode(Opcodes.IFGT, null);
                    mn.instructions.add(jmp);
                    break;
                case GREATER_EQUAL:
                    jmp = new JumpInsnNode(Opcodes.IFGE, null);
                    mn.instructions.add(jmp);
                    break;
                case LESS:
                    jmp = new JumpInsnNode(Opcodes.IFLT, null);
                    mn.instructions.add(jmp);
                    break;
                case LESS_EQUAL:
                    jmp = new JumpInsnNode(Opcodes.IFLE, null);
                    mn.instructions.add(jmp);
                    break;
                default:
                    ASTUtils.error(node, "Operator not supported");
                    break;
                }
                mn.instructions.add(new InsnNode(Opcodes.ICONST_0));
                LabelNode endLabelNode = new LabelNode();
                mn.instructions.add(new JumpInsnNode(Opcodes.GOTO, endLabelNode));
                LabelNode trueLabelNode = new LabelNode();
                jmp.label = trueLabelNode;
                mn.instructions.add(trueLabelNode);
                mn.instructions.add(new InsnNode(Opcodes.ICONST_1));
                mn.instructions.add(endLabelNode);
            } else if (type.equals(Type.INT_TYPE)) {
                LabelNode trueLabelNode = new LabelNode();
                switch (op) {
                case EQUAL:
                    mn.instructions.add(new JumpInsnNode(Opcodes.IF_ICMPEQ, trueLabelNode));
                    break;
                case NOT_EQUAL:
                    mn.instructions.add(new JumpInsnNode(Opcodes.IF_ICMPNE, trueLabelNode));
                    break;
                case GREATER:
                    mn.instructions.add(new JumpInsnNode(Opcodes.IF_ICMPGT, trueLabelNode));
                    break;
                case GREATER_EQUAL:
                    mn.instructions.add(new JumpInsnNode(Opcodes.IF_ICMPGE, trueLabelNode));
                    break;
                case LESS:
                    mn.instructions.add(new JumpInsnNode(Opcodes.IF_ICMPLT, trueLabelNode));
                    break;
                case LESS_EQUAL:
                    mn.instructions.add(new JumpInsnNode(Opcodes.IF_ICMPLE, trueLabelNode));
                    break;
                default:
                    break;
                }
                mn.instructions.add(new InsnNode(Opcodes.ICONST_0));
                LabelNode endLabelNode = new LabelNode();
                mn.instructions.add(new JumpInsnNode(Opcodes.GOTO, endLabelNode));
                mn.instructions.add(trueLabelNode);
                mn.instructions.add(new InsnNode(Opcodes.ICONST_1));
                mn.instructions.add(endLabelNode);
            } else {
                ASTUtils.error(node, "Cannot compare such types.");
            }
        } else {
            ASTUtils.error(node, "Operator not recognized.");
        }
    }

    /**
     * Assumes top of stack contains two strings
     */
    private void handleStringOperator(ASTNode node, Operator op) throws ASTVisitorException {
        if (op.equals(Operator.PLUS)) {
            mn.instructions.add(new TypeInsnNode(Opcodes.NEW, "java/lang/StringBuilder"));
            mn.instructions.add(new InsnNode(Opcodes.DUP));
            mn.instructions.add(
                    new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V", false));
            mn.instructions.add(new InsnNode(Opcodes.SWAP));
            mn.instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append",
                    "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false));
            mn.instructions.add(new InsnNode(Opcodes.SWAP));
            mn.instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append",
                    "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false));
            mn.instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "toString",
                    "()Ljava/lang/String;", false));
        } else if (op.isRelational()) {
            LabelNode trueLabelNode = new LabelNode();
            switch (op) {
            case EQUAL:
                mn.instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/String", "equals",
                        "(Ljava/lang/Object;)Z", false));
                mn.instructions.add(new JumpInsnNode(Opcodes.IFNE, trueLabelNode));
                break;
            case NOT_EQUAL:
                mn.instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/String", "equals",
                        "(Ljava/lang/Object;)Z", false));
                mn.instructions.add(new JumpInsnNode(Opcodes.IFEQ, trueLabelNode));
                break;
            default:
                ASTUtils.error(node, "Operator not supported on strings");
                break;
            }
            mn.instructions.add(new InsnNode(Opcodes.ICONST_0));
            LabelNode endLabelNode = new LabelNode();
            mn.instructions.add(new JumpInsnNode(Opcodes.GOTO, endLabelNode));
            mn.instructions.add(trueLabelNode);
            mn.instructions.add(new InsnNode(Opcodes.ICONST_1));
            mn.instructions.add(endLabelNode);
        } else {
            ASTUtils.error(node, "Operator not recognized");
        }
    }

    @Override
    public void visit(AccessorExpression node) throws ASTVisitorException {
        node.getExpression().accept(this);
        //function access
        if (node.getExpressions() != null) {

            node.getExpressions().accept(this);

            //if expressionS length is 0, no args privided
            Type returnType;
            Type exprClass = ASTUtils.getSafeType(node.getExpression());
            SymTable<SymTableEntry> sTable = ASTUtils.getSafeEnv(node);
            SymTableEntry lookup = sTable.lookup(node.getIdentifier());
            System.out.println(
                    "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$4 " + node.getIdentifier());
            if (lookup != null) {
                mn.instructions.add(
                        new MethodInsnNode(Opcodes.INVOKEVIRTUAL, exprClass.getInternalName(), node.getIdentifier(),
                                Type.getMethodDescriptor(lookup.getType(), lookup.getParametersTypes()), false));
            } else {
                Map<Type, SymTable<SymTableEntry>> classes = Registry.getInstance().getClasses();
                Iterator<Map.Entry<Type, SymTable<SymTableEntry>>> entries = classes.entrySet().iterator();
                while (entries.hasNext()) {
                    Map.Entry<Type, SymTable<SymTableEntry>> entry = entries.next();
                    if (entry.getValue().lookup(node.getIdentifier()) != null) {
                        SymTableEntry lookup1 = entry.getValue().lookup(node.getIdentifier());
                        System.out.println("entry key: " + entry.getKey().getDescriptor());
                        mn.instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
                                entry.getKey().getInternalName(), node.getIdentifier(),
                                Type.getMethodDescriptor(lookup1.getType(), lookup1.getParametersTypes()), false));
                        break;
                    }
                }
            }
        }
        //field access
        else {
            System.out.println("+++++++++++++++++++++++++> HEY " + node.getIdentifier());
            if (node.getExpression().getClass() != IdentifierExpression.class && previousIsIdentifier) {
                System.out.println("+++++++++++++++++++++++++++++++++++++++++++---> " + node.getIdentifier());
                mn.instructions.add(new FieldInsnNode(Opcodes.GETFIELD, cn.name, node.getIdentifier(),
                        ASTUtils.getSafeType(node).getDescriptor()));
            } else {
                mn.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, cn.name, node.getIdentifier(),
                        ASTUtils.getSafeType(node).getDescriptor()));
            }

        }
    }

    @Override
    public void visit(AssignmentStatement node) throws ASTVisitorException {

        node.getExpression2().accept(this);
        Type exprType2 = ASTUtils.getSafeType(node.getExpression2());

        node.getExpression1().accept(this);
        Type exprType1 = ASTUtils.getSafeType(node.getExpression1());

        Type type = ASTUtils.getSafeType(node.getExpression2());

        LocalIndexPool lip = ASTUtils.getSafeLocalIndexPool(node);
        int li = lip.getLocalIndex(type);
        //tests
        SymTable<SymTableEntry> sTable = ASTUtils.getSafeEnv(node.getExpression1());
        Integer index = ASTUtils.getIndex(node.getExpression1());
        System.out.println(
                "***** class: " + node.getExpression1().getClass() + " index: " + index + " old index: " + li);
        widen(exprType1, exprType2);
        //        mn.instructions.add(new VarInsnNode(exprType2.getOpcode(Opcodes.ISTORE), li));
        lip.freeLocalIndex(li, type);
    }

    @Override
    public void visit(BinaryExpression node) throws ASTVisitorException {
        node.getExpression1().accept(this);
        Type expr1Type = ASTUtils.getSafeType(node.getExpression1());

        node.getExpression2().accept(this);
        Type expr2Type = ASTUtils.getSafeType(node.getExpression2());

        Type maxType = TypeUtils.maxType(expr1Type, expr2Type);

        // cast top of stack to max
        if (!maxType.equals(expr2Type)) {
            widen(maxType, expr2Type);
        }
        System.out.println("^^^^^^^^^^^^^^^^^^^ binary op: " + node.getOperator());
        System.out.println("             type1: " + expr1Type + " type2: " + expr2Type);
        System.out.println("                max type: " + !maxType.equals(expr1Type));
        // cast second from top to max
        if (!maxType.equals(expr1Type)) {
            System.out.println("not to be dispalyed");
            LocalIndexPool lip = ASTUtils.getSafeLocalIndexPool(node);
            int localIndex = -1;
            if (expr2Type.equals(Type.DOUBLE_TYPE) || expr1Type.equals(Type.DOUBLE_TYPE)) {
                localIndex = lip.getLocalIndex(expr2Type);
                mn.instructions.add(new VarInsnNode(expr2Type.getOpcode(Opcodes.ISTORE), localIndex));
            } else {
                mn.instructions.add(new InsnNode(Opcodes.SWAP));
            }
            widen(maxType, expr1Type);
            if (expr2Type.equals(Type.DOUBLE_TYPE) || expr1Type.equals(Type.DOUBLE_TYPE)) {
                mn.instructions.add(new VarInsnNode(expr2Type.getOpcode(Opcodes.ILOAD), localIndex));
                lip.freeLocalIndex(localIndex, expr2Type);
            } else {
                mn.instructions.add(new InsnNode(Opcodes.SWAP));
            }
        }

        // 
        if (ASTUtils.isBooleanExpression(node)) {
            handleBooleanOperator(node, node.getOperator(), maxType);
        } else if (maxType.equals(TypeUtils.STRING_TYPE)) {
            mn.instructions.add(new InsnNode(Opcodes.SWAP));
            handleStringOperator(node, node.getOperator());
        } else {
            handleNumberOperator(node, node.getOperator(), maxType);
        }
    }

    @Override
    public void visit(BreakStatement node) throws ASTVisitorException {
        JumpInsnNode jmp = new JumpInsnNode(Opcodes.GOTO, null);
        mn.instructions.add(jmp);
        ASTUtils.getBreakList(node).add(jmp);
    }

    @Override
    public void visit(ClassDefinition node) throws ASTVisitorException {
        ClassNode classNode = new ClassNode();
        cn = classNode;

        cn.version = Opcodes.V1_5;
        cn.superName = "java/lang/Object";
        cn.name = node.getIdentifier();
        cn.access = Opcodes.ACC_PUBLIC;

        // create constructor
        mn = new MethodNode(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
        mn.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
        mn.instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false));
        mn.instructions.add(new InsnNode(Opcodes.RETURN));

        mn.maxLocals = 1;
        mn.maxStack = 1;
        classNode.methods.add(mn);

        node.getFfDefinitions().accept(this);

        // IMPORTANT: this should be dynamically calculated
        // use COMPUTE_MAXS when computing the ClassWriter,
        // e.g. new ClassWriter(ClassWriter.COMPUTE_MAXS)
        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
        //         ClassVisitor ca = new CheckClassAdapter(cw);
        //         cn.accept(new CheckClassAdapter(ca));
        TraceClassVisitor cv = new TraceClassVisitor(cw, new PrintWriter(System.out));

        cn.accept(cv);
        //get code
        byte code[] = cw.toByteArray();

        Logger.getLogger(BytecodeGeneratorASTVisitor.class.getName())
                .info("Writing " + node.getIdentifier() + " class to .class file");
        // update to file
        FileOutputStream fos;
        try {
            fos = new FileOutputStream(node.getIdentifier() + ".class");
            fos.write(code);
            fos.close();
        } catch (FileNotFoundException ex) {
            Logger.getLogger(BytecodeGeneratorASTVisitor.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(BytecodeGeneratorASTVisitor.class.getName()).log(Level.SEVERE, null, ex);
        }

        cn = null;
        System.out.println("##### finished writing to file");

    }

    @Override
    public void visit(CompUnit node) throws ASTVisitorException {
        for (ClassDefinition cd : node.getClassDefinitions()) {
            cd.accept(this);
        }
    }

    @Override
    public void visit(CompoundStatement node) throws ASTVisitorException {
        node.getStatements().accept(this);
    }

    @Override
    public void visit(ContinueStatement node) throws ASTVisitorException {
        JumpInsnNode jmp = new JumpInsnNode(Opcodes.GOTO, null);
        mn.instructions.add(jmp);
        ASTUtils.getContinueList(node).add(jmp);
    }

    @Override
    public void visit(DeclarationStatement node) throws ASTVisitorException {
        SymTable<SymTableEntry> sTable = ASTUtils.getSafeEnv(node);
        SymTableEntry lookup = sTable.lookup(node.getIdentifier());
        node.getType().accept(this);
        //nothing??
    }

    @Override
    public void visit(FloatLiteralExpression node) throws ASTVisitorException {
        if (ASTUtils.isBooleanExpression(node)) {
            JumpInsnNode i = new JumpInsnNode(Opcodes.GOTO, null);
            mn.instructions.add(i);
            if (node.getLiteral() != 0) {
                ASTUtils.getTrueList(node).add(i);
            } else {
                ASTUtils.getFalseList(node).add(i);
            }
        } else {
            Float d = node.getLiteral();
            mn.instructions.add(new LdcInsnNode((d)));
        }
    }

    @Override
    public void visit(ExpressionList node) throws ASTVisitorException {
        if (!node.getExpressions().isEmpty()) { //if there is a list of expressions
            for (Expression e : node.getExpressions()) {
                e.accept(this);
            }
        }
    }

    @Override
    public void visit(ExpressionStatement node) throws ASTVisitorException {
        node.getExpression().accept(this);
    }

    @Override
    public void visit(FFDefinitionsList node) throws ASTVisitorException {
        if (!node.getFfDefinitons().isEmpty()) {
            for (FFDefinition ffd : node.getFfDefinitons()) {
                ffd.accept(this);
            }
        }
    }

    @Override
    public void visit(FieldDefinition node) throws ASTVisitorException {
        cn.fields.add(new FieldNode(Opcodes.ACC_PUBLIC, node.getIdentifier(),
                node.getType().getTypeSpecifier().getDescriptor(), null, null));
    }

    @Override
    public void visit(FunctionDefinition node) throws ASTVisitorException {
        fd = node;
        //fix the signature       
        System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~ " + node.getIdentifier()
                + " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
        if (node.getStorageSpecifier() == null) { //if the function is static
            LocalIndexPool safeLocalIndexPool = ASTUtils.getSafeLocalIndexPool(node);
            int localIndex = safeLocalIndexPool.getLocalIndex();
        }
        LocalIndexPool safeLocalIndexPool = ASTUtils.getSafeLocalIndexPool(node);
        String methodType = Type.getMethodDescriptor(node.getType().getTypeSpecifier(),
                node.getParameters().getParameterTypes());
        int accessor = Opcodes.ACC_PUBLIC;
        if (ASTUtils.getIsStatic(node)) {
            accessor = accessor + Opcodes.ACC_STATIC;
        }
        MethodNode methodNode;
        if (node.getIdentifier().equals("main")) {
            methodNode = new MethodNode(accessor, node.getIdentifier(), "([Ljava/lang/String;)V", null, null);
        } else {
            methodNode = new MethodNode(accessor, node.getIdentifier(), methodType, null, null);
        }
        mn = methodNode;

        node.getParameters().accept(this);
        node.getCompoundStatement().accept(this);

        mn.instructions.add(new InsnNode(Opcodes.RETURN));
        //            mn.maxLocals = 30;
        //        mn.maxStack = 30;

        cn.methods.add(mn);

        fd = null;
        mn = null;
    }

    @Override
    public void visit(IdentifierExpression node) throws ASTVisitorException {
        previousIsIdentifier = false;
        if (node.getExpressions() != null) {
            node.getExpressions().accept(this);
            SymTable<SymTableEntry> symbols = Registry.getInstance()
                    .getExistingClass(Type.getType("Lorg/hua/customclasses/" + cn.name + ";"));
            SymTableEntry sEntry = symbols.lookup(node.getIdentifier());
            if (sEntry != null) {
                mn.instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
                        Type.getType("Lorg/hua/customclasses/" + cn.name + ";").getInternalName(),
                        node.getIdentifier(), Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE), false));
            } else {
                //search all classes
                //if the function is static and defined in another class, ok
                //else error
                String nodeId = node.getIdentifier();
                boolean foundStaticOtherClass = false;
                String classFound;
                Map<Type, SymTable<SymTableEntry>> classes = Registry.getInstance().getClasses();
                Iterator<Map.Entry<Type, SymTable<SymTableEntry>>> entries = classes.entrySet().iterator();
                while (entries.hasNext()) {
                    Map.Entry<Type, SymTable<SymTableEntry>> entry = entries.next();
                    if (entry.getValue().lookup(nodeId) != null) {
                        if (entry.getValue().lookup(nodeId).isIsStatic()) {
                            foundStaticOtherClass = true;
                            classFound = entry.getKey().toString();
                            break;
                        }
                    }
                }
                if (!foundStaticOtherClass) {
                    ASTUtils.error(node, "This static(?) method could not be found");
                }
            }
        } else {

            Type type = ASTUtils.getSafeType(node);
            SymTable<SymTableEntry> symbols = Registry.getInstance()
                    .getExistingClass(Type.getType("Lorg/hua/customclasses/" + cn.name + ";"));
            SymTableEntry csEntry = symbols.lookup(node.getIdentifier());
            //i think this is useless, because fields are not seperate identifier, but string ids in accessorExpressions
            if (csEntry != null) {

                mn.instructions.add(new FieldInsnNode(Opcodes.GETFIELD, cn.name, node.getIdentifier(),
                        csEntry.getType().getDescriptor()));
                return;
            }
            SymTable<SymTableEntry> sTable = ASTUtils.getSafeEnv(node);
            SymTableEntry sEntry = sTable.lookup(node.getIdentifier());

            previousIsIdentifier = true;
            mn.instructions.add(new VarInsnNode(type.getOpcode(Opcodes.ILOAD), sEntry.getIndex()));
            System.out.println(
                    "&&&&&&&&&&&&&&&&&&&&&&&&&&&& INDEX: " + sEntry.getIndex() + " id: " + node.getIdentifier());
        }
    }

    @Override
    public void visit(IfElseStatement node) throws ASTVisitorException {
        ASTUtils.setBooleanExpression(node.getExpression(), true);
        node.getExpression().accept(this);

        LabelNode stmt1StartLabelNode = new LabelNode();
        mn.instructions.add(stmt1StartLabelNode);
        node.getStatement1().accept(this);

        JumpInsnNode skipGoto = new JumpInsnNode(Opcodes.GOTO, null);
        mn.instructions.add(skipGoto);

        LabelNode stmt2StartLabelNode = new LabelNode();
        mn.instructions.add(stmt2StartLabelNode);
        node.getStatement2().accept(this);

        backpatch(ASTUtils.getTrueList(node.getExpression()), stmt1StartLabelNode);
        backpatch(ASTUtils.getFalseList(node.getExpression()), stmt2StartLabelNode);

        ASTUtils.getNextList(node).addAll(ASTUtils.getNextList(node.getStatement1()));
        ASTUtils.getNextList(node).addAll(ASTUtils.getNextList(node.getStatement2()));
        ASTUtils.getNextList(node).add(skipGoto);

        ASTUtils.getBreakList(node).addAll(ASTUtils.getBreakList(node.getStatement1()));
        ASTUtils.getBreakList(node).addAll(ASTUtils.getBreakList(node.getStatement2()));

        ASTUtils.getContinueList(node).addAll(ASTUtils.getContinueList(node.getStatement1()));
        ASTUtils.getContinueList(node).addAll(ASTUtils.getContinueList(node.getStatement2()));
    }

    @Override
    public void visit(IfStatement node) throws ASTVisitorException {
        ASTUtils.setBooleanExpression(node.getExpression(), true);

        node.getExpression().accept(this);

        LabelNode labelNode = new LabelNode();
        mn.instructions.add(labelNode);
        backpatch(ASTUtils.getTrueList(node.getExpression()), labelNode);

        node.getStatement().accept(this);

        ASTUtils.getBreakList(node).addAll(ASTUtils.getBreakList(node.getStatement()));
        ASTUtils.getContinueList(node).addAll(ASTUtils.getContinueList(node.getStatement()));

        ASTUtils.getNextList(node).addAll(ASTUtils.getFalseList(node.getExpression()));
        ASTUtils.getNextList(node).addAll(ASTUtils.getNextList(node.getStatement()));
    }

    @Override
    public void visit(IntegerLiteralExpression node) throws ASTVisitorException {
        if (ASTUtils.isBooleanExpression(node)) {
            JumpInsnNode i = new JumpInsnNode(Opcodes.GOTO, null);
            mn.instructions.add(i);
            if (node.getLiteral() != 0) {
                ASTUtils.getTrueList(node).add(i);
            } else {
                ASTUtils.getFalseList(node).add(i);
            }
        } else {
            Integer d = node.getLiteral();
            mn.instructions.add(new LdcInsnNode(d));
        }
    }

    @Override
    public void visit(NullExpression node) throws ASTVisitorException {
        mn.instructions.add(new VarInsnNode(Opcodes.ILOAD, Opcodes.NULL));
    }

    @Override
    public void visit(ParameterDeclaration node) throws ASTVisitorException {
        node.getType().accept(this);
        //is the access flag private?

        mn.parameters.add(new ParameterNode(node.getIdentifier(), Opcodes.ACC_PRIVATE));
        System.out.println("hereeeee " + node.getIdentifier());
    }

    @Override
    public void visit(ParameterList node) throws ASTVisitorException {
        if (!node.getParameters().isEmpty()) {
            mn.parameters = new ArrayList<ParameterNode>();
            for (ParameterDeclaration pd : node.getParameters()) {
                System.out.println("~~~~ param " + pd.getClass());
                pd.accept(this);

            }
        }
    }

    @Override
    public void visit(ParenthesisExpression node) throws ASTVisitorException {
        node.getExpression().accept(this);
    }

    @Override
    public void visit(ReturnStatement node) throws ASTVisitorException {
        if (node.getExpression() != null) {
            node.getExpression().accept(this);
            SymTable<SymTableEntry> sTable = ASTUtils.getSafeEnv(node);
            mn.instructions.add(new VarInsnNode(Opcodes.RETURN, 0));
        } else {
            mn.instructions.add(new InsnNode(Opcodes.RETURN));
        }
    }

    @Override
    public void visit(StatementList node) throws ASTVisitorException {
        Statement s = null, ps;
        Iterator<Statement> it = node.getStatements().iterator();
        while (it.hasNext()) {

            ps = s;
            s = it.next();

            if (ps != null && !ASTUtils.getNextList(ps).isEmpty()) {
                LabelNode labelNode = new LabelNode();
                mn.instructions.add(labelNode);
                backpatch(ASTUtils.getNextList(ps), labelNode);
            }
            s.accept(this);
            if (!ASTUtils.getBreakList(s).isEmpty()) {
                ASTUtils.error(s, "Break detected without a loop.");
            }

            if (!ASTUtils.getContinueList(s).isEmpty()) {
                ASTUtils.error(s, "Continue detected without a loop.");
            }

        }

        if (s != null && !ASTUtils.getNextList(s).isEmpty()) {
            LabelNode labelNode = new LabelNode();
            mn.instructions.add(labelNode);
            backpatch(ASTUtils.getNextList(s), labelNode);
        }

    }

    @Override
    public void visit(StringLiteralExpression node) throws ASTVisitorException {
        String s = node.getLiteral();
        System.out.println(
                "25252525252252525252525225252525252525225252525252552522252525252525252252525252525525222525252525252522525252525255252");
        mn.instructions.add(new LdcInsnNode(s));
    }

    @Override
    public void visit(ThisExpression node) throws ASTVisitorException {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void visit(UnaryExpression node) throws ASTVisitorException {
        node.getExpression().accept(this);

        Type type = ASTUtils.getSafeType(node.getExpression());

        if (node.getOperator().equals(Operator.MINUS)) {
            mn.instructions.add(new InsnNode(type.getOpcode(Opcodes.INEG)));
        } else {
            ASTUtils.error(node, "Operator not recognized.");
        }
    }

    @Override
    public void visit(WhileStatement node) throws ASTVisitorException {
        ASTUtils.setBooleanExpression(node.getExpression(), true);

        LabelNode beginLabelNode = new LabelNode();
        mn.instructions.add(beginLabelNode);

        node.getExpression().accept(this);

        LabelNode trueLabelNode = new LabelNode();
        mn.instructions.add(trueLabelNode);
        backpatch(ASTUtils.getTrueList(node.getExpression()), trueLabelNode);

        node.getStatement().accept(this);

        backpatch(ASTUtils.getNextList(node.getStatement()), beginLabelNode);
        backpatch(ASTUtils.getContinueList(node.getStatement()), beginLabelNode);

        mn.instructions.add(new JumpInsnNode(Opcodes.GOTO, beginLabelNode));

        ASTUtils.getNextList(node).addAll(ASTUtils.getFalseList(node.getExpression()));
        ASTUtils.getNextList(node).addAll(ASTUtils.getBreakList(node.getStatement()));
    }

    @Override
    public void visit(WriteStatement node) throws ASTVisitorException {

        Type type = ASTUtils.getSafeType(node.getExpression());
        LocalIndexPool lip = ASTUtils.getSafeLocalIndexPool(node);
        int li = lip.getLocalIndex(type);
        mn.instructions
                .add(new FieldInsnNode(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"));
        System.out.println(
                "***************************************************************-------------------------------------------------------------- "
                        + li);
        mn.instructions.add(new VarInsnNode(type.getOpcode(Opcodes.ILOAD), 0));
        node.getExpression().accept(this);
        mn.instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "print",
                Type.getMethodType(Type.VOID_TYPE, type).toString(), false));
        lip.freeLocalIndex(li, type);
    }

    @Override
    public void visit(TypeSpecifier node) throws ASTVisitorException {
        //        System.out.println("im here "+node.getTypeSpecifier());
    }

    @Override
    public void visit(NewIdentifierExpression node) throws ASTVisitorException {
        if (node.getExpressions() != null) {
            node.getExpressions().accept(this);
        }
        mn.instructions.add(new TypeInsnNode(Opcodes.NEW, node.getIdentifier()));
        mn.instructions.add(new InsnNode(Opcodes.DUP));
        //@TODO: fix calling parameters
        if (node.getExpressions() != null) {
            if (node.getExpressions().getExpressions().isEmpty() && Registry.getInstance()
                    .classExists(Type.getType("Lorg/hua/customclasses/" + node.getIdentifier() + ";"))) {
                System.out.println("222222222222222222222222222222222222222222 "
                        + ASTUtils.getSafeType(node).getInternalName());
                mn.instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL,
                        ASTUtils.getSafeType(node).getInternalName(), "<init>", "()V", false));
            } else //get parameter types and then give that as the signature
            if (Registry.getInstance()
                    .classExists(Type.getType("Lorg/hua/customclasses/" + node.getIdentifier() + ";"))) {
                SymTable<SymTableEntry> existingClass = Registry.getInstance()
                        .getExistingClass(Type.getType("Lorg/hua/customclasses/" + node.getIdentifier() + ";"));
                SymTableEntry lookup = existingClass.lookup(node.getIdentifier());
                if (lookup != null) {
                    Type[] types = lookup.getParametersTypes();
                    mn.instructions.add(
                            new MethodInsnNode(Opcodes.INVOKEVIRTUAL, ASTUtils.getSafeType(node).getInternalName(),
                                    node.getIdentifier(), Type.getMethodDescriptor(Type.VOID_TYPE, types), false));
                } else {
                    ASTUtils.error(node, "Constructor not found");
                }
            } else {
                ASTUtils.error(node, "Problem with called constructor");
            }
        }
        LocalIndexPool pool = ASTUtils.getSafeLocalIndexPool(fd);
        int localIndex = pool.getLocalIndex();
        System.out.println("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ "
                + localIndex);
        mn.instructions.add(new VarInsnNode(Opcodes.ASTORE, localIndex));
    }

    /**
     * Cast the top of the stack to a particular type
     */
    private void widen(Type target, Type source) {
        if (source.equals(target)) {
            return;
        }

        if (source.equals(Type.BOOLEAN_TYPE)) {
            if (target.equals(Type.INT_TYPE)) {
                // nothing
            } else if (target.equals(Type.DOUBLE_TYPE)) {
                mn.instructions.add(new InsnNode(Opcodes.I2D));
            } else if (target.equals(TypeUtils.STRING_TYPE)) {
                mn.instructions.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "java/lang/Boolean", "toString",
                        "(Z)Ljava/lang/String;", false));
            }
        } else if (source.equals(Type.INT_TYPE)) {
            if (target.equals(Type.DOUBLE_TYPE)) {
                mn.instructions.add(new InsnNode(Opcodes.I2D));
            } else if (target.equals(TypeUtils.STRING_TYPE)) {
                mn.instructions.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "java/lang/Integer", "toString",
                        "(I)Ljava/lang/String;", false));
            }
        } else if (source.equals(Type.DOUBLE_TYPE)) {
            if (target.equals(TypeUtils.STRING_TYPE)) {
                mn.instructions.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "java/lang/Double", "toString",
                        "(D)Ljava/lang/String;", false));
            }
        }
    }

}