@Override
 public DataType visitFactor(@NotNull PythonParser.FactorContext ctx) {
   if (ctx.power() != null) {
     return visitPower(ctx.power());
   } else if (ctx.factor() != null) {
     DataType type = visitFactor(ctx.factor());
     if (type.isInteger()) {
       if (ctx.PLUS() != null) {
         return type;
       } else if (ctx.MINUS() != null) {
         mv.visitInsn(INEG);
         return type;
       }
     } else if (type.isBoolean()) {
       if (ctx.PLUS() != null) {
         return type;
       } else if (ctx.MINUS() != null) {
         mv.visitInsn(INEG);
         return PrimitiveType.INTEGER;
       }
     } else {
       if (ctx.PLUS() != null) {
         throw new CompileException(
             String.format("Doing %s with %s is making no sense!", ctx.PLUS().getText(), type));
       } else if (ctx.MINUS() != null) {
         throw new CompileException(
             String.format("Doing %s with %s is making no sense!", ctx.MINUS().getText(), type));
       }
     }
   }
   throw new CompileException(
       String.format(
           "Something gone wrong! Please write to [email protected] with example test."));
 }
  @Override
  public DataType visitAtom(@NotNull PythonParser.AtomContext ctx) {
    //        System.out.println("Zz" + ctx.NAME() + ctx.STRING());
    if (ctx.test() != null) { // 1
      return visitTest(ctx.test());
    } else if (ctx.STRING().size() > 0) { // 7,8,9
      String ss = "";
      for (TerminalNode s : ctx.STRING()) {
        ss += s.getText();
      }
      mv.visitLdcInsn(ss.length());
      mv.visitIntInsn(NEWARRAY, T_CHAR);
      int tempIndex = 0;
      for (int i = 0; i < ss.length(); i++) {
        if (!("\"".equals(ss.substring(i, i + 1))) && !("\'".equals(ss.substring(i, i + 1)))) {
          mv.visitInsn(DUP);
          mv.visitLdcInsn(tempIndex);
          mv.visitLdcInsn(ss.charAt(i));
          mv.visitInsn(CASTORE);
          tempIndex++;
        }
      }
      if (ctx.LBRACK() != null) {
        if (Integer.parseInt(ctx.INT().getText()) > tempIndex - 1) {
          throw new CompileException(
              String.format(
                  "Index out of bounds exception for string %s with index %s",
                  ss, Integer.parseInt(ctx.INT().getText())));
        }
        mv.visitLdcInsn(Integer.parseInt(ctx.INT().getText()));
        mv.visitInsn(CALOAD);
        mv.visitMethodInsn(
            INVOKESTATIC,
            Type.getType(String.class).getInternalName(),
            "valueOf",
            "(C)Ljava/lang/String;",
            false);
        return new StringType(1);
      } else {
        mv.visitMethodInsn(
            INVOKESTATIC,
            Type.getType(String.class).getInternalName(),
            "valueOf",
            "([C)Ljava/lang/String;",
            false);
        return new StringType(ss.length());
      }
    } else if (!ctx.NAME().isEmpty()) { // 3,4,5
      DataType type = null;
      //            System.out.println("GG" + ctx.getText() + "GG");
      String varName = ctx.NAME().get(0).getText();
      if (scope.isLocalVariable(varName)) {
        if (ctx.LBRACK() != null) { // 4,5
          type = scope.getLocalVariableType(varName);
          if (!(type instanceof StringType)) {
            throw new CompileException(String.format("Trying to take index not from string!!"));
          }
          mv.visitVarInsn(type.isPrimitive() ? ILOAD : ALOAD, scope.getLocalVariableIndex(varName));
          if (ctx.INT() != null) {
            mv.visitMethodInsn(
                INVOKEVIRTUAL,
                Type.getType(String.class).getInternalName(),
                "toCharArray",
                "()[C",
                false);
            if (Integer.parseInt(ctx.INT().getText()) > type.getSize()) {
              throw new CompileException(String.format("Index out of bounds exception!"));
            }
            mv.visitLdcInsn(Integer.parseInt(ctx.INT().getText()));
            mv.visitInsn(CALOAD);
            mv.visitMethodInsn(
                INVOKESTATIC,
                Type.getType(String.class).getInternalName(),
                "valueOf",
                "(C)Ljava/lang/String;",
                false);
            return new StringType(1);
          } else if (ctx.NAME(1) != null) {
            varName = ctx.NAME(1).getText();
            type = scope.getLocalVariableType(ctx.NAME(1).getText());
            if (!type.isInteger()) {
              throw new CompileException(
                  String.format("Trying to take index from string not with int!"));
            } else {
              Label okLabel = new Label();
              mv.visitMethodInsn(
                  INVOKEVIRTUAL,
                  Type.getType(String.class).getInternalName(),
                  "toCharArray",
                  "()[C",
                  false);
              mv.visitVarInsn(ILOAD, scope.getLocalVariableIndex(ctx.NAME(1).getText()));
              mv.visitInsn(DUP);
              mv.visitLdcInsn(type.getSize());
              mv.visitInsn(SWAP);
              mv.visitJumpInsn(IF_ICMPGT, okLabel);
              mv.visitLabel(okLabel);
              mv.visitInsn(CALOAD);
              mv.visitMethodInsn(
                  INVOKESTATIC,
                  Type.getType(String.class).getInternalName(),
                  "valueOf",
                  "(C)Ljava/lang/String;",
                  false);
              // TODO out of bounds a[b]
              //                            mv.visitLdcInsn("Out of bounds!");
              //                            mv.visitMethodInsn(INVOKESPECIAL,
              //                                    "java/lang/CompilerException", "<init>",
              // "(Ljava/lang/String;)V", false);
              return new StringType(1);
            }

          } else {
            throw new CompileException(String.format("Unidentified operation"));
          }
        } else { // 3
          type = scope.getLocalVariableType(varName);
          mv.visitVarInsn(type.isPrimitive() ? ILOAD : ALOAD, scope.getLocalVariableIndex(varName));
        }
      } else if (scope.isGlobalVariable(varName)) {
        if (ctx.LBRACK() != null) { // 4,5
          type = scope.getGlobalVariableType(varName);
          if (!(type instanceof StringType)) {
            throw new CompileException(String.format("Trying to take index not from string!!"));
          }
          mv.visitFieldInsn(
              GETSTATIC, scope.getClassName(), varName, type.getType().getDescriptor());
          if (ctx.INT() != null) {
            mv.visitMethodInsn(
                INVOKEVIRTUAL,
                Type.getType(String.class).getInternalName(),
                "toCharArray",
                "()[C",
                false);
            if (Integer.parseInt(ctx.INT().getText()) > type.getSize()) {
              throw new CompileException(String.format("Index out of bounds exception!"));
            }
            mv.visitLdcInsn(Integer.parseInt(ctx.INT().getText()));
            mv.visitInsn(CALOAD);
            mv.visitMethodInsn(
                INVOKESTATIC,
                Type.getType(String.class).getInternalName(),
                "valueOf",
                "(C)Ljava/lang/String;",
                false);
            return new StringType(1);
          } else if (ctx.NAME(1) != null) {
            varName = ctx.NAME(1).getText();
            type = scope.getLocalVariableType(ctx.NAME(1).getText());
            if (!type.isInteger()) {
              throw new CompileException(
                  String.format("Trying to take index from string not with int!"));
            } else {
              Label okLabel = new Label();
              mv.visitMethodInsn(
                  INVOKEVIRTUAL,
                  Type.getType(String.class).getInternalName(),
                  "toCharArray",
                  "()[C",
                  false);
              mv.visitVarInsn(ILOAD, scope.getLocalVariableIndex(ctx.NAME(1).getText()));
              mv.visitInsn(DUP);
              mv.visitLdcInsn(type.getSize());
              mv.visitInsn(SWAP);
              mv.visitJumpInsn(IF_ICMPGT, okLabel);
              mv.visitLabel(okLabel);
              mv.visitInsn(CALOAD);
              mv.visitMethodInsn(
                  INVOKESTATIC,
                  Type.getType(String.class).getInternalName(),
                  "valueOf",
                  "(C)Ljava/lang/String;",
                  false);
              // TODO out of bounds a[b]
              //                            mv.visitLdcInsn("Out of bounds!");
              //                            mv.visitMethodInsn(INVOKESPECIAL,
              //                                    "java/lang/CompilerException", "<init>",
              // "(Ljava/lang/String;)V", false);
              return new StringType(1);
            }

          } else {
            throw new CompileException(String.format("Unidentified operation"));
          }
        } else { // 3
          type = scope.getGlobalVariableType(varName);
          mv.visitFieldInsn(
              GETSTATIC, scope.getClassName(), varName, type.getType().getDescriptor());
        }
      }
      return type;
      //			} else if (scope.isFunction)
    } else if (ctx.INT() != null) { // 6
      mv.visitLdcInsn(Integer.parseInt(ctx.INT().getText()));
      return PrimitiveType.INTEGER;
    } else if (ctx.BOOL() != null) { // 2
      mv.visitInsn("False".equals(ctx.BOOL().getText()) ? ICONST_0 : ICONST_1);
      return PrimitiveType.BOOLEAN;
    } else {
      throw new CompileException(String.format("Undefined thing to work with! %s", ctx.getText()));
    }
  }