public void conditionExpressionShouldBeBoolean() {
    ModuleEnvironment conditionExpressionType = _typeCheckingStack.pop();
    ModuleEnvironment boolType = ApplicationMainSymbolTable.getModuleByName("bool");

    if (conditionExpressionType.isSubtypeOf(boolType) == false)
      throw new ConditionExpressionMustBeBooleanException();
  }
  private Signature createSignature(ArrayList<ModuleEnvironment> parameterTypes) {
    Signature signature = new Signature();
    for (ModuleEnvironment parameter : parameterTypes)
      signature.addArgument("", parameter.getName());

    return signature;
  }
  public void unaryMinusOperator() {
    ModuleEnvironment unaryMinusOperandType = _typeCheckingStack.pop();
    ModuleEnvironment intType = ApplicationMainSymbolTable.getModuleByName("int");

    if (unaryMinusOperandType.isSubtypeOf(intType)) _typeCheckingStack.push(intType);
    else throw new TypeOfUnaryMinusOperatorMustBeIntException();
  }
  public void notOperator() {
    ModuleEnvironment operandType = _typeCheckingStack.pop();
    ModuleEnvironment boolType = ApplicationMainSymbolTable.getModuleByName("bool");

    if (operandType.isSubtypeOf(boolType)) _typeCheckingStack.push(boolType);
    else throw new TypesOfBooleanOperatorsMustBeBooleanException();
  }
  public void checkArrayIndexType() {
    ModuleEnvironment arrayIndexType = _typeCheckingStack.pop();
    ModuleEnvironment intType = ApplicationMainSymbolTable.getModuleByName("int");

    if (arrayIndexType.isSubtypeOf(intType) == false) {
      _typeCheckingStack.pop();
      throw new ArrayIndexTypeMustBeIntException();
    }
  }
  private void binaryBooleanOperator() {
    ModuleEnvironment rightOperandType = _typeCheckingStack.pop();
    ModuleEnvironment leftOperandType = _typeCheckingStack.pop();
    ModuleEnvironment boolType = ApplicationMainSymbolTable.getModuleByName("bool");

    if (rightOperandType.isSubtypeOf(boolType) && leftOperandType.isSubtypeOf(boolType))
      _typeCheckingStack.push(boolType);
    else throw new TypesOfBooleanOperatorsMustBeBooleanException();
  }
  private String fetchParameteresAndMethodName(ArrayList<ModuleEnvironment> parameterTypes) {
    ModuleEnvironment parameterType = _typeCheckingStack.pop();
    while ((parameterType instanceof FrameModuleEnvironment) == false) {
      parameterTypes.add(0, parameterType);
      parameterType = _typeCheckingStack.pop();
    }

    String calledMethodName = parameterType.getName();
    return calledMethodName;
  }
  private boolean isSubTypeOfBaseTypes() {
    ModuleEnvironment variableType = _typeCheckingStack.pop();
    ModuleEnvironment boolType = ApplicationMainSymbolTable.getModuleByName("bool");
    ModuleEnvironment intType = ApplicationMainSymbolTable.getModuleByName("int");
    ModuleEnvironment stringType = ApplicationMainSymbolTable.getModuleByName("string");

    return variableType.isSubtypeOf(boolType)
        || variableType.isSubtypeOf(intType)
        || variableType.isSubtypeOf(stringType);
  }
  public void checkReturnType(Environment environment) {
    environment = getContainerMethodEnvironment(environment);

    ModuleEnvironment returnTypeStatement = getReturnTypeStatement();
    MethodEnvironment currentMethod = (MethodEnvironment) environment;
    ModuleEnvironment methodReturnType =
        ApplicationMainSymbolTable.getModuleByName(currentMethod.getReturnTypeName());

    if (returnTypeStatement.isSubtypeOf(methodReturnType) == false)
      throw new ReturnTypeMustBeSubTypeOfMethodReturnType();
  }
  public void assignmentOperator() {
    ModuleEnvironment rightType = _typeCheckingStack.pop();
    ModuleEnvironment leftType = _typeCheckingStack.pop();

    if (rightType.isSubtypeOf(leftType) == false) throw new TypeMismatchException();
  }
 private boolean haveSameType(
     ModuleEnvironment rightOperandType,
     ModuleEnvironment leftOperandType,
     ModuleEnvironment type) {
   return rightOperandType.isSubtypeOf(type) && leftOperandType.isSubtypeOf(type);
 }