public Scope visitFile_input(@NotNull PythonParser.File_inputContext ctx, String name) {
    if (ctx == null)
      throw new IllegalArgumentException("No input context! Something wrong while lexing-parsing!");
    init();
    scope.setClassName(name);
    cw.visit(V1_7, ACC_PUBLIC, name, null, "java/lang/Object", null);

    mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);

    for (PythonParser.StmtContext sctx : ctx.stmt()) visitStmt(sctx);
    mv.visitInsn(RETURN);
    mv.visitMaxs(0, 0);
    mv.visitEnd();

    cw.visitEnd();
    scope.setByteCode(cw.toByteArray());
    return scope;
  }
 @Override
 public DataType visitWhile_stmt(@NotNull PythonParser.While_stmtContext ctx) {
   Label continueLabel = new Label();
   Label breakLabel = new Label();
   Label elseLabel = new Label();
   scope.enterLoop(continueLabel, breakLabel);
   mv.visitLabel(continueLabel);
   visitTest(ctx.test());
   //        verifyType(visitExpression(ctx.expression()), PrimitiveType.BOOLEAN, ctx);
   mv.visitJumpInsn(IFEQ, elseLabel);
   visitSuite(ctx.suite(0));
   mv.visitJumpInsn(GOTO, continueLabel);
   mv.visitLabel(elseLabel);
   if (ctx.suite(1) != null) visitSuite(ctx.suite(1));
   mv.visitLabel(breakLabel);
   scope.exitLoop();
   return null;
 }
 @Override
 public DataType visitFuncdef(@NotNull PythonParser.FuncdefContext ctx) {
   String name = ctx.NAME().getText();
   scope.setMethodName(name);
   String[] argumentNames = visitParameters(ctx.parameters());
   Integer numberParms = argumentNames.length;
   //        System.out.println(name + numberParms);
   scope.declareFunction(name, numberParms);
   scope.addFunctionSuite(name, numberParms, ctx.suite());
   scope.addFunctionArgumentsNames(name, numberParms, argumentNames);
   //        mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, name, "()V", null, null);//TODO to
   // function call
   //        visitSuite(ctx.suite());
   //        mv.visitMaxs(0, 0);
   //        mv.visitEnd();
   //        scope.setMethodName(name);
   //        scope.refreshLocalVariables();
   return null;
 }
  @Override
  public DataType visitGlobal_stmt(@NotNull PythonParser.Global_stmtContext ctx) {
    for (TerminalNode e : ctx.NAME()) {
      scope.addGlobalVariable(e.getText(), PrimitiveType.INTEGER);
      String descriptor = PrimitiveType.INTEGER.getType().getDescriptor();
      Object value = PrimitiveType.INTEGER.isPrimitive() ? 0 : null;
      cw.visitField(ACC_PUBLIC | ACC_STATIC, e.getText(), descriptor, null, value).visitEnd();
    }

    return PrimitiveType.INTEGER;
  }
  @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 visitPower(@NotNull PythonParser.PowerContext ctx) {
    //        System.out.println("called!");

    if (ctx.trailer() != null)
      if (ctx.atom().NAME() != null) {
        String name = ctx.atom().NAME(0).getText();
        Integer argumentGiven = 0;
        String returnSignatue = "V";
        String argSignature = "";
        String totalSinature = "";

        if (ctx.trailer().arglist() != null) {
          argumentGiven = ctx.trailer().arglist().argument().size();
        }
        if (!scope.isFunctionDeclared(name))
          throw new CompileException(String.format("Function %s is not defined.", name));
        else {
          Integer argumentsCount = scope.functionArgumentCount(name);
          if (!argumentsCount.equals(argumentGiven)) {
            throw new CompileException(
                String.format(
                    "Function %s takes exactly %s arguments (%s given)",
                    name, argumentsCount, argumentGiven));
          } else {
            if (argumentGiven == 0) {
              argSignature = "";
            } else {
              int i = 0;
              String[] argumentsNames = scope.getFunctionArgumentsNames(name, argumentGiven);
              for (PythonParser.ArgumentContext argctx : ctx.trailer().arglist().argument()) {
                DataType argType = visitArgument(argctx);
                argSignature += argType.getType().getDescriptor();
                // System.out.println("Хуйня тут" + argType + argumentsNames[i]);
                scope.addLocalVariable(argumentsNames[i], argType);
                //                                int opcode =
                // scope.getLocalVariableType(argumentsNames[i]).isPrimitive() ? ISTORE : ASTORE;
                //                                mv.visitVarInsn(opcode,
                // scope.getLocalVariableIndex(argumentsNames[i]));
                i++;
              }
            }

            totalSinature = "(" + argSignature + ")" + returnSignatue;
            System.out.println("ACTION!" + totalSinature);
            MethodVisitor mvSave = mv;
            mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, name, totalSinature, null, null);
            visitSuite(scope.getFunctionSuite(name, argumentGiven));
            mv.visitInsn(RETURN);
            mv.visitMaxs(0, 0);
            mv.visitEnd();
            scope.setMethodName(name);
            scope.refreshLocalVariables();
            mv = mvSave;
            mv.visitMethodInsn(INVOKESTATIC, scope.getClassName(), name, totalSinature, false);
          }
        }

        //                //TODO function with () call {a()} + default values
        //                DataType returnType = scope.getFunctionReturnType(name, argumentType);
        //                mv.visitMethodInsn(INVOKESTATIC, scope.getClassName(), name,
        // Utils.getFunctionDescriptor(returnType, argumentType), false);
        //                System.out.println("called!");
        return null;

      } else {
        throw new CompileException(
            String.format("%s object is not callable!", ctx.atom().getText()));
      }
    return visitAtom(ctx.atom());
  }
 @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;
 }
 @Override
 public DataType visitContinue_stmt(@NotNull PythonParser.Continue_stmtContext ctx) {
   if (!scope.inLoop()) throw new CompileException("Continue is out of loop " + ctx.getText());
   mv.visitJumpInsn(GOTO, scope.getContinueLabel());
   return null;
 }