protected void buildLiterals(ClassWriter cw, EnumClassDefinition classDef) {
    FieldVisitor fv;
    for (EnumLiteralDefinition lit : classDef.getEnumLiterals()) {
      fv =
          cw.visitField(
              ACC_PUBLIC + ACC_FINAL + ACC_STATIC + ACC_ENUM,
              lit.getName(),
              BuildUtils.getTypeDescriptor(classDef.getClassName()),
              null,
              null);
      fv.visitEnd();
    }

    {
      fv =
          cw.visitField(
              ACC_PRIVATE + ACC_FINAL + ACC_STATIC + ACC_SYNTHETIC,
              "$VALUES",
              "[" + BuildUtils.getTypeDescriptor(classDef.getClassName()),
              null,
              null);
      fv.visitEnd();
    }
  }
  protected void buildConstructors(ClassWriter cw, EnumClassDefinition classDef)
      throws IOException, ClassNotFoundException {
    MethodVisitor mv;
    String argTypes = "";
    int size = 0;
    for (FieldDefinition fld : classDef.getFieldsDefinitions()) {
      argTypes += BuildUtils.getTypeDescriptor(fld.getTypeName());
      size += BuildUtils.sizeOf(fld.getTypeName());
    }

    {
      int ofs = 3;

      mv =
          cw.visitMethod(
              ACC_PRIVATE,
              "<init>",
              "(Ljava/lang/String;I" + argTypes + ")V",
              "(" + argTypes + ")V",
              null);
      mv.visitCode();
      mv.visitVarInsn(ALOAD, 0);
      mv.visitVarInsn(ALOAD, 1);
      mv.visitVarInsn(ILOAD, 2);
      mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Enum", "<init>", "(Ljava/lang/String;I)V");
      for (FieldDefinition fld : classDef.getFieldsDefinitions()) {
        mv.visitVarInsn(ALOAD, 0);
        mv.visitVarInsn(BuildUtils.varType(fld.getTypeName()), ofs);
        mv.visitFieldInsn(
            PUTFIELD,
            BuildUtils.getInternalType(classDef.getName()),
            fld.getName(),
            BuildUtils.getTypeDescriptor(fld.getTypeName()));
        ofs += BuildUtils.sizeOf(fld.getTypeName());
      }
      mv.visitInsn(RETURN);
      mv.visitMaxs(3, ofs);
      mv.visitEnd();
    }

    {
      mv = cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
      mv.visitCode();

      int N = classDef.getEnumLiterals().size();

      mv.visitTypeInsn(NEW, BuildUtils.getInternalType(classDef.getClassName()));

      for (int j = 0; j < N; j++) {
        EnumLiteralDefinition lit = classDef.getEnumLiterals().get(j);
        mv.visitInsn(DUP);
        mv.visitLdcInsn(lit.getName());
        BuildUtils.pushInt(mv, j);

        List<String> args = lit.getConstructorArgs();
        for (int k = 0; k < args.size(); k++) {
          String argType = classDef.getField(k).getTypeName();

          mv.visitLdcInsn(args.get(k));
          mv.visitMethodInsn(
              INVOKESTATIC, "org/mvel2/MVEL", "eval", "(Ljava/lang/String;)Ljava/lang/Object;");

          if (BuildUtils.isPrimitive(argType)) {
            mv.visitTypeInsn(CHECKCAST, BuildUtils.getInternalType(BuildUtils.box(argType)));
            mv.visitMethodInsn(
                INVOKEVIRTUAL,
                BuildUtils.getInternalType(BuildUtils.box(argType)),
                BuildUtils.numericMorph(BuildUtils.box(argType)),
                "()" + BuildUtils.getTypeDescriptor(argType));
          } else {
            mv.visitTypeInsn(CHECKCAST, BuildUtils.getInternalType(argType));
          }
        }

        mv.visitMethodInsn(
            INVOKESPECIAL,
            BuildUtils.getInternalType(classDef.getClassName()),
            "<init>",
            "(Ljava/lang/String;I" + argTypes + ")V");
        mv.visitFieldInsn(
            PUTSTATIC,
            BuildUtils.getInternalType(classDef.getClassName()),
            lit.getName(),
            BuildUtils.getTypeDescriptor(classDef.getClassName()));
        mv.visitTypeInsn(NEW, BuildUtils.getInternalType(classDef.getClassName()));
      }

      BuildUtils.pushInt(mv, N);
      mv.visitTypeInsn(ANEWARRAY, BuildUtils.getInternalType(classDef.getClassName()));

      for (int j = 0; j < N; j++) {
        EnumLiteralDefinition lit = classDef.getEnumLiterals().get(j);
        mv.visitInsn(DUP);
        BuildUtils.pushInt(mv, j);
        mv.visitFieldInsn(
            GETSTATIC,
            BuildUtils.getInternalType(classDef.getClassName()),
            lit.getName(),
            BuildUtils.getTypeDescriptor(classDef.getClassName()));
        mv.visitInsn(AASTORE);
      }

      mv.visitFieldInsn(
          PUTSTATIC,
          BuildUtils.getInternalType(classDef.getClassName()),
          "$VALUES",
          "[" + BuildUtils.getTypeDescriptor(classDef.getClassName()));

      mv.visitInsn(RETURN);
      mv.visitMaxs(4 + size, 0);
      mv.visitEnd();
    }

    {
      mv =
          cw.visitMethod(
              ACC_PUBLIC + ACC_STATIC,
              "valueOf",
              "(Ljava/lang/String;)" + BuildUtils.getTypeDescriptor(classDef.getClassName()),
              null,
              null);
      mv.visitCode();
      mv.visitLdcInsn(Type.getType(BuildUtils.getTypeDescriptor(classDef.getClassName())));
      mv.visitVarInsn(ALOAD, 0);
      mv.visitMethodInsn(
          INVOKESTATIC,
          "java/lang/Enum",
          "valueOf",
          "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;");
      mv.visitTypeInsn(CHECKCAST, BuildUtils.getInternalType(classDef.getClassName()));
      mv.visitInsn(ARETURN);
      mv.visitMaxs(2, 1);
      mv.visitEnd();
    }
  }