@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()));
    }
  }
 @Override
 public DataType visitExpr_stmt(@NotNull PythonParser.Expr_stmtContext ctx) {
   if (ctx.power() != null) {
     if (ctx.power().atom().NAME() != null && ctx.power().atom().STRING().size() == 0) {
       String var = ctx.power().atom().NAME().get(0).getText();
       if (ctx.power().atom().LBRACK() != null) {
         if (scope.isLocalVariable(var)) {
           if (!(scope.getLocalVariableType(var) instanceof StringType)) {
             throw new CompileException(String.format("Trying to take index not from string!"));
           }
         } else if (scope.isGlobalVariable(var)) {
           if (!(scope.getGlobalVariableType(var) instanceof StringType)) {
             throw new CompileException(String.format("Trying to take index not from string!"));
           }
         }
         throw new CompileException(
             String.format("Assigning to element of String is not implemented yet!"));
         //                    if (ctx.power().atom().INT() != null) {
         //
         //                    } else {
         //
         //                    }
       } else {
         if (ctx.test() != null) {
           if (ctx.power().trailer() != null) {
             throw new CompileException(String.format("Can't assign to function!"));
           }
           DataType etype = visitTest(ctx.test());
           if (scope.isLocalVariable(var)) {
             //                System.out.println("LOCAL" + var + "e" + etype +  "e" +
             // scope.getLocalVariableType(var) );
             if (etype.equals(scope.getLocalVariableType(var))) {
               //                    System.out.println("Type not changing!");
               int opcode = scope.getLocalVariableType(var).isPrimitive() ? ISTORE : ASTORE;
               mv.visitVarInsn(opcode, scope.getLocalVariableIndex(var));
             } else {
               //                    System.out.println("Type changing!");
               scope.changeLocalVariableType(var, etype);
               int opcode = etype.isPrimitive() ? ISTORE : ASTORE;
               mv.visitVarInsn(opcode, scope.getLocalVariableIndex(var));
             }
           } else if (scope.isGlobalVariable(var)) {
             DataType vtype = scope.getGlobalVariableType(var);
             mv.visitFieldInsn(
                 PUTSTATIC, scope.getClassName(), var, vtype.getType().getDescriptor());
             //                        } else if (scope.isFunctionDeclared(var)) {    TODO
           } else {
             scope.addLocalVariable(var, etype);
             int opcode = scope.getLocalVariableType(var).isPrimitive() ? ISTORE : ASTORE;
             mv.visitVarInsn(opcode, scope.getLocalVariableIndex(var));
             // throw new CompileException(String.format("Variable %s not found in context %s.",
             // var, ctx.getText()));
           }
           return etype;
         } else if (ctx.power().trailer() != null) { // is function
           visitPower(ctx.power());
           //                        if
           // (!scope.isFunctionDeclared(ctx.power().atom().NAME(0).getText(),
           // ctx.power().trailer().arglist().argument().size()))
           //                            throw new CompileException(String.format("Function %s not
           // defined.", var));
           //                        else
           //                            System.out.println("ACTION!");
         } else if (scope.isLocalVariable(var)) {
           return scope.getLocalVariableType(var);
         } else if (scope.isGlobalVariable(var)) {
           return scope.getGlobalVariableType(var);
         } else throw new CompileException(String.format("Variable %s not defined.", var));
       }
     } else {
       throw new CompileException(String.format("can't assign to operator"));
     }
   } else {
     System.out.println("Something bad happened!");
   }
   return null;
 }