Primes with prime bit-counts

Python 2, 106 102 100 bytes

k=m=1;p={0}
exec"p^={m%k*k,0};c=bin(k).count\nif{k,c('1'),c('0')-1}<p:print k\nm*=k*k;k+=1;"*input()

Try it online!

Background

To identify primes, we use a corollary of Wilson's theorem:

corollary of Wilson's theorem

How it works

We start by initializing k and m as 1 and p as the set {0}. Note that m = 1 = 0!² = (k - 1)!². Immediately afterwards, the following code is executed n times, where n is the integer read from standard input.

p^={m%k*k,0};c=bin(k).count
if{k,c('1'),c('0')-1}<p:print k
m*=k*k;k+=1

By the corollary, m % k will be 1 if k is prime and 0 otherwise. Thus, {m%k*k,0} will return the set {k, 0} if k is prime and the set {0} otherwise.

If (and only if) k is prime, since p cannot contain k at this point, the in-place symmetric difference p^={m%k*k,0} will add k to the set p. Also, p will contain 0 after the update if and only if it does not contain 0 before, so 0 ∊ p if and only if k is even.

On the same line, we define a function c via c=bin(k).count, which will count the occurrences of its argument in k's binary representation.

The second line produces the actual output. {k,c('1'),c('0')-1} returns the set that consists of k itself, the number of set bits in k, and the number of unset bits in k. Since the output of bin(k) begins with 0b, we have to decrement c('0') to account for the leading 0.

If all of them are prime, they will all belong to p, which by now contains all prime numbers up to k (and potentially 0). If k is a Mersenne number (i.e., if it has only set bits), c('0')-1 will yield 0. Since Mersenne numbers are odd, p will not contain 0, so the condition will fail.

After (potentially) printing k, we multiply m by . Since m = (k-1)!² before the update, m = k!² after it. After incrementing k, the relation m = (k-1)!² holds again and we're ready for the next iteration.


Mathematica, 80 68 54 bytes

Select[p=PrimeQ;Range@#,p@#&&And@@p/@#~DigitCount~2&]&

Explanation

Select[p=PrimeQ;Range@#,p@#&&And@@p/@#~DigitCount~2&]&

       p=PrimeQ                                        (* Store prime check func. in p *)
Select[                                             ]  (* Select *)
                Range@#                                (* from a list {1..n} *)
                        p@#                            (* numbers that are prime *)
                           &&                          (* And *)
                                     #~DigitCount~2    (* whose digit counts in binary *)
                             And@@p/@                  (* are prime as well *)

JavaScript (ES6), 123 118 115 111 104 96 bytes

Saved 4 bytes thanks to @Arnauld

G=n=>n?G(n>>1,++a[n%2]):a.some(n=>(P=x=>n%--x?P(x):x)(n)-1)
F=n=>F(n-1,G(n,a=[0,0,n])||alert(n))

A combination of three typical recursive functions. Alerts the sequence in reverse order and terminates on a "too much recursion" error.

Test snippet

(modified to output to the page)

alert = s => O.textContent += s + "\n"

G=n=>n?G(n>>1,++a[n%2]):a.some(n=>(P=x=>n%--x?P(x):x)(n)-1)
F=n=>F(n-1,G(n,a=[0,0,n])||alert(n))

F(1000)
<pre id=O></pre>

The main function can return an array for 104 bytes:

G=n=>n?G(n>>1,++a[n%2]):a.some(n=>(P=x=>n%--x?P(x):x)(n)-1)
F=n=>n?F(n-1).concat(G(n,a=[0,0,n])?[]:n):[]

It can also be non-recursive at the cost of another byte:

G=n=>n?G(n>>1,++a[n%2]):a.some(n=>(P=x=>n%--x?P(x):x)(n)-1)
n=>[for(_ of Array(n))if(!G(--n,a=[0,0,n]))n]

Here's the one I started with: (Saved 6 bytes thanks to @Arnauld)

P=(n,x=n)=>n>1&--x<2||n%x&&P(n,x)
G=n=>n?G(n>>1,o+=n%2,t++):P(o)&P(t-o)
F=n=>n?F(n-1).concat(P(n)&G(n,o=t=0)?n:[]):[]

I tried golfing this further and managed to do it in 104 bytes—then realized I had already found that solution (it's at the bottom of the answer). Don't you hate it when that happens? :P

A non-recursive attempt at the main function (again, same byte count):

n=>[for(i of Array(n))if(P(--n)&G(n,o=t=0))n]

This one takes the easy route of counting how many 0's and 1's are in the binary representation:

F=n=>n?F(n-1).concat([n,(G=x=>n.toString(2).split(x).length-1)(0),G(1)].some(n=>(P=x=>n%--x?P(x):x)(n)-1)?[]:n):[]

Same thing with an array comprehension:

n=>[for(_ of Array(n))if(![--n,(G=x=>n.toString(2).split(x).length-1)(0),G(1)].some(n=>(P=x=>n%--x?P(x):x)(n)-1))n]

This one takes a slightly harder route to do the same thing:

F=n=>n?F(n-1).concat([n,(G=(x,w=n)=>w&&G(x,w>>1)+(w%2==x))(0),G(1)].some(n=>(P=x=>n%--x?P(x):x)(n)-1)?[]:n):[]

And this one takes yet another related route that's as short as the original:

F=n=>n?F(n-1).concat([n,o=(G=x=>x&&x%2+G(n>>++t))(n,t=0),t-o].some(n=>(P=x=>n%--x?P(x):x)(n)-1)?[]:n):[]

Again, you can golf 8 bytes by making it alert the sequence in reverse order:

F=n=>F(n-1,[n,o=(G=x=>x&&x%2+G(n>>++t))(n,t=0),t-o].some(n=>(P=x=>n%--x?P(x):x)(n)-1)||alert(n))