JavaScriptが記号だけで書ける言語であることはよく知られています。
たとえば、以下のようなプログラムを実行すればHello, World!
とコンソールに表示されますね。
[][[[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]][[]]=[[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]]+[]][+[]][++[++[++[+[]][+[]]][+[]]][+[]]]+[[+[]==[]]+[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[[]==[]]+[]][+[]][++[++[++[+[]][+[]]][+[]]][+[]]]+[[+[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[]][+[]][++[+[]][+[]]]+[[+[]==[]]+[]][+[]][++[++[+[]][+[]]][+[]]]+[[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]]+[]][+[]][++[++[++[+[]][+[]]][+[]]][+[]]]+[[+[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[]][+[]][++[+[]][+[]]]]+[[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]][+[]]=[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]][[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]][[]]]]+[[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]][++[+[]][+[]]]=[[+[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]]][+[]][++[+[]][+[]]+[+[]]]+[[]+[]][+[]][[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]][[]]][[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[[]==[]]+[]][+[]][++[+[]][+[]]]+[[+[]][+[]][[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]][[]]]+[]][+[]][++[+[]][+[]]+[++[+[]][+[]]]]+[[+[]==[]]+[]][+[]][++[++[++[+[]][+[]]][+[]]][+[]]]]]+[[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]][[]==[]]=[+[++[++[+[]][+[]]][+[]]+[++[++[++[++[++[+[]][+[]]][+[]]][+[]]][+[]]][+[]]]]][+[]][[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]][++[+[]][+[]]]](++[++[++[+[]][+[]]][+[]]][+[]]+[+[]])]+[[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]][+[]==[]]=[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]][[]==[]]+[[+[]==[]]+[]][+[]][++[+[]][+[]]]+[[+[]==[]]+[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[]][+[]][+[]]+[[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]][+[]]()+[]][+[]][++[+[]][+[]]+[++[++[++[+[]][+[]]][+[]]][+[]]]]+[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]][[]==[]]+[[+[]==[]]+[]][+[]][++[++[++[+[]][+[]]][+[]]][+[]]]]+[[][[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]][[]]][[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]][+[]==[]]][[]]=[][[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]][[]]][[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]][+[]==[]]]]+[[][[]][++[+[]][+[]]]=[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]][[]]]+[[][[]][++[++[+[]][+[]]][+[]]]=[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]][+[]]]+[[][[]][++[+[]][+[]]+[+[]]]=[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]][++[+[]][+[]]]]+[[][[]][++[++[+[]][+[]]][+[]]+[+[]]]=[[]+[]][+[]][[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]][[]]]]+[[][[]][[][++[++[+[]][+[]]][+[]]]]=[][++[++[+[]][+[]]][+[]]]([[+[]==[]]+[]][+[]][++[+[]][+[]]]+[[+[]==[]]+[]][+[]][++[++[++[+[]][+[]]][+[]]][+[]]]+[[+[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[]][+[]][++[++[+[]][+[]]][+[]]]+[[+[]==[]]+[]][+[]][++[+[]][+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]]+[]][+[]][++[++[++[+[]][+[]]][+[]]][+[]]+[++[+[]][+[]]]]+[[+[]==[]]+[]][+[]][++[++[++[+[]][+[]]][+[]]][+[]]]+[[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]]+[]][+[]][++[++[+[]][+[]]][+[]]+[++[++[++[+[]][+[]]][+[]]][+[]]]]+[[[]==[]]+[]][+[]][++[+[]][+[]]]+[[[]==[]]+[]][+[]][++[++[+[]][+[]]][+[]]])()]+[[][[]][[][[][++[++[+[]][+[]]][+[]]]]]=[][++[++[+[]][+[]]][+[]]]([[+[]==[]]+[]][+[]][++[+[]][+[]]]+[[+[]==[]]+[]][+[]][++[++[++[+[]][+[]]][+[]]][+[]]]+[[+[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[]][+[]][++[++[+[]][+[]]][+[]]]+[[+[]==[]]+[]][+[]][++[+[]][+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]]+[]][+[]][++[++[++[+[]][+[]]][+[]]][+[]]+[++[+[]][+[]]]]+[[[]==[]]+[]][+[]][++[+[]][+[]]]+[[[]==[]]+[]][+[]][++[++[++[+[]][+[]]][+[]]][+[]]]+[[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]][+[]]()+[]][+[]][++[+[]][+[]]+[++[++[++[+[]][+[]]][+[]]][+[]]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]]+[]][+[]][++[++[++[+[]][+[]]][+[]]][+[]]]+[[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]]+[]][+[]][++[++[++[+[]][+[]]][+[]]][+[]]+[++[+[]][+[]]]]+[][++[++[+[]][+[]]][+[]]]())()]+[[][[]][++[+[]][+[]]+[++[+[]][+[]]]]=[][[[+[]==[]]+[]][+[]][++[++[++[+[]][+[]]][+[]]][+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[]][+[]][++[+[]][+[]]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[]][+[]][++[++[++[+[]][+[]]][+[]]][+[]]]+[[[]==[]]+[]][+[]][++[++[++[+[]][+[]]][+[]]][+[]]]]()[[][[]][++[+[]][+[]]]]]+[[][[]][[][[][[][++[++[+[]][+[]]][+[]]]]]]=[[[]+[]][+[]][[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]][[]]]+[]][+[]][++[+[]][+[]]+[++[++[++[++[+[]][+[]]][+[]]][+[]]][+[]]]]+[[+[]==[]]+[]][+[]][++[++[++[+[]][+[]]][+[]]][+[]]]+[[+[]==[]]+[]][+[]][+[]]+[+[]+[][++[+[]][+[]]+[++[+[]][+[]]]]][+[]][++[+[]][+[]]+[+[]]]+[+[++[++[++[+[]][+[]]][+[]]][+[]]+[++[++[+[]][+[]]][+[]]]]][+[]][[][++[+[]][+[]]+[+[]]]](++[++[++[+[]][+[]]][+[]]][+[]]+[++[++[++[+[]][+[]]][+[]]][+[]]])+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[+[]+[][[][[][++[++[+[]][+[]]][+[]]]]]()[[][[]][++[+[]][+[]]]]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[]][+[]][++[+[]][+[]]]+[[+[]==[]]+[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]]][+[]][++[+[]][+[]]+[+[]]]+[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]][[]==[]]+[[+[]==[]]+[]][+[]][++[++[++[+[]][+[]]][+[]]][+[]]]+[[+[]==[]]+[]][+[]][++[+[]][+[]]]+[[+[]==[]]+[]][+[]][+[]]+[[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]][+[]]()+[]][+[]][++[+[]][+[]]+[++[++[++[+[]][+[]]][+[]]][+[]]]]+[+[]+[+[]][+[]][[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]][[]]]][+[]][++[+[]][+[]]+[+[]]]+[[[]==[]]+[]][+[]][++[+[]][+[]]]+[[+[]][+[]][[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]][[]]]+[]][+[]][++[+[]][+[]]+[++[+[]][+[]]]]+[[+[]==[]]+[]][+[]][++[++[++[+[]][+[]]][+[]]][+[]]]+[[[]==[]]+[]][+[]][++[++[++[+[]][+[]]][+[]]][+[]]]]+[[][[]][[][[][[][[][++[++[+[]][+[]]][+[]]]]]]]=[][++[++[+[]][+[]]][+[]]+[+[]]][[][++[+[]][+[]]+[++[+[]][+[]]]][[][[][[][[][++[++[+[]][+[]]][+[]]]]]]]([][++[++[+[]][+[]]][+[]]+[+[]]])[[[[]==[]]+[]][+[]][++[++[++[+[]][+[]]][+[]]][+[]]]+[[+[]==[]]+[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[]][+[]][++[+[]][+[]]]+[[+[]==[]]+[]][+[]][+[]]]()[+[]]]]+[][[][++[++[+[]][+[]]][+[]]]]([[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]]+[]][+[]][++[++[++[+[]][+[]]][+[]]][+[]]]+[[+[]==[]]+[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[[]==[]]+[]][+[]][++[++[++[+[]][+[]]][+[]]][+[]]]+[[+[]==[]]+[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]]][+[]][++[+[]][+[]]+[+[]]]+[[[]==[]]+[]][+[]][++[++[+[]][+[]]][+[]]]+[[+[]==[]]+[]][+[]][++[++[++[+[]][+[]]][+[]]][+[]]]+[][[][[][[][[][++[++[+[]][+[]]][+[]]]]]]](++[++[++[++[+[]][+[]]][+[]]][+[]]][+[]]+[++[++[++[++[++[++[+[]][+[]]][+[]]][+[]]][+[]]][+[]]][+[]]])+[[[]==[]]+[]][+[]][++[++[+[]][+[]]][+[]]]+[[+[]==[]]+[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]]][+[]][++[+[]][+[]]+[+[]]]+[[[]+[]][+[]][[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]][[]]]+[]][+[]][++[+[]][+[]]+[++[++[++[++[+[]][+[]]][+[]]][+[]]][+[]]]])([][[][[][[][[][++[++[+[]][+[]]][+[]]]]]]](++[++[++[++[++[++[++[+[]][+[]]][+[]]][+[]]][+[]]][+[]]][+[]]][+[]]+[++[++[+[]][+[]]][+[]]])+[[+[]==[]]+[]][+[]][++[++[++[+[]][+[]]][+[]]][+[]]]+[[[]==[]]+[]][+[]][++[++[+[]][+[]]][+[]]]+[[[]==[]]+[]][+[]][++[++[+[]][+[]]][+[]]]+[[+[]==[]]+[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]]][+[]][++[+[]][+[]]+[+[]]]+[][[][[][[][[][++[++[+[]][+[]]][+[]]]]]]](++[++[++[++[+[]][+[]]][+[]]][+[]]][+[]]+[++[++[++[++[+[]][+[]]][+[]]][+[]]][+[]]])+[[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]]+[]][+[]][++[++[++[+[]][+[]]][+[]]][+[]]+[++[+[]][+[]]]]+[][[][[][[][[][++[++[+[]][+[]]][+[]]]]]]](++[++[++[++[++[++[++[++[+[]][+[]]][+[]]][+[]]][+[]]][+[]]][+[]]][+[]]][+[]]+[++[++[++[++[++[++[++[+[]][+[]]][+[]]][+[]]][+[]]][+[]]][+[]]][+[]]])+[[+[]==[]]+[][[[[]==[]]+[]][+[]][+[]]+[[+[]==[]]+[+[]]+[][+[]]+[]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[][+[]]][+[]][++[+[]][+[]]+[+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]]][+[]][++[+[]][+[]]+[+[]]]+[[+[]==[]]+[]][+[]][++[+[]][+[]]]+[[[]==[]]+[]][+[]][++[++[+[]][+[]]][+[]]]+[[][+[]]+[]][+[]][++[++[+[]][+[]]][+[]]]+[][[][[][[][[][++[++[+[]][+[]]][+[]]]]]]](++[++[++[+[]][+[]]][+[]]][+[]]+[++[++[++[+[]][+[]]][+[]]][+[]]]))]
// Hello, World!
このことに関する解説記事も、Qiita上でいくつか執筆されています。
一方で、従来のQiita記事では「記号のみを使って」いればそれでよいとする制約が多く、使用される記号の種類に関する制約を課している例は見つけることができませんでした。
本記事では、記号のみを使ってJavaScriptを書くだけでなく、使用する記号の種類を極力少なくすることも考慮します。
その上で、JavaScriptプログラムを記号のみを用いて表現するための小手先のテクニックについて解説をしていきたいと思います。
それではやってみましょう。
レギュレーション
古来より、JavaScriptで任意のプログラムを書くために必要な最小の記号の数は6種類であるとされてきました。1
今回はそれに倣い、ルールを以下のように決めます。
- プログラム中に使用してよいのは、
[]()+=
の6種類の記号のみ。 - ブラウザとnode.jsの両方で動作しなければならない。
- よって、明示的な
window
やglobal
へのアクセスは禁止。globalThis
2もまだ存在しないということにしておきます。 - 実行環境は記事執筆時点でのnode.jsとChromeの最新安定版とします。
- よって、明示的な
記号プログラミングことはじめ
基本的な考え方
JavaScriptでは、a
というオブジェクトのプロパティをa["x"]
のようにして取得することができます。
つまり、console.log()
はconsole["log"]()
として呼び出すことができます。
これは、 任意の文字列 と[]
と()
の記号があればメソッドの実行が可能になることを意味します。
また、JavaScriptでは至る所で暗黙の型変換3が行われ、気がついたら文字列が数値になっていたりオブジェクトが文字列になっていたりします。
たとえば、
+[] // 0
[]+[] // ""
true+"" // "true"
false+"" // "false"
(function f(){})+"" // "function f(){}"
(false+"")[1] // "a"
この愉快極まりない挙動を利用することで何もないところから文字列を拾ってきて、それを利用してプロパティにアクセスする、というのが記号プログラミングの最初の考え方になります。
はじめに+[]
があった
数を得る
+[]
は0
ですが、ここから任意の非負整数値を得ることができます。
++[+[]][+[]] // 1
これは実行すると1
になります。
Ctrl + Shift + I
キーあたりを押すとJavaScriptの実行コンソールが開くかもしれないので、実際に実行して試してみましょう。
+[]
が0
になるので、上のコードは以下のように読み替えることができます。
++[0][0]
左の[0]
は0
が入った要素1の配列ですから、右の[0]
で0番目の要素にアクセスすると0
が得られますね。
前置の++
によってこの0
をインクリメントすることで1
を得ています。4
2
以降も同様に作れます。5
++[++[+[]][+[]]][+[]] // 2
++[++[++[+[]][+[]]][+[]]][+[]] // 3
以後簡単のため、++[+[]][+[]]
のかわりに1
などと書いたりすることがあります。
undefinedとNaNと文字列キャスト
[][[]] // undefined (存在しない配列要素へのアクセス)
+[][[]] // NaN (undefinedを+で数値にキャスト)
[][[]] +[] // "undefined" (undefinedを文字列に変換)
+[][[]] +[] // "NaN"
[ [][[]] +[] ] [0][0] // "u"
[ [][[]] +[] ] [0][1] // "n"
[ [][[]] +[] ] [0][2] // "d"
[+[][[]] +[] ] [0][0] // "N"
存在しないプロパティにアクセスすることで、undefined
も得ることができます。
また、x+[]
は、x
を文字列に変換する力を持っており、undefined
は文字列に変換すると"undefined"
となります。
私たちは今、0
,1
,2
,...とundefined
, NaN
, そしていくつかの文字にアクセスすることができるようになりました。
はじめてのプロパティアクセス 6
ところで"undefined"
の文字列から、"find"
を取り出すことができます。
こうですね。
const find = "undefined"[4] + "undefined"[5] + "undefined"[1] + "undefined"[2] // "find"
このおかげで、Array.prototype.find
にアクセスできます。
[]["find"] // === Array.prototype.find
[]["find"] +[] // "function find() { [native code] }"
"function find() { [native code] }"
からは"function"
に含まれる文字をはじめとしていくつかの文字を取り出すことができますね。
ちなみにこれまでのコードを省略せず[]+
の記号だけで書くと、以下のようになります。
// === Array.prototype.find
[][[[][[]]+[]][+[]][++[++[++[++[+[]][+[]]][+[]]][+[]]][+[]]]+[[][[]]+[]][+[]][++[++[++[++[++[+[]][+[]]][+[]]][+[]]][+[]]][+[]]]+[[][[]]+[]][+[]][++[+[]][+[]]]+[[][[]]+[]][+[]][++[++[+[]][+[]]][+[]]]]
この程度なら、まだ人間でも手書きできますね。
結局のところ、[]+
の三種類の記号によって、
0123456789
acdefinotuvy
IN
{}[]() +-.
これだけの文字が得られるということが知られています。 (http://slides.com/sylvainpv/xchars-js/#/16)
今回紹介していない要素として、三種類の記号からInfinity
や"-"
、負の整数も得ることができます。
https://github.com/aemkei/jsfuck が(この記事が必要なくなるぐらいに)非常によくまとまっているので、興味があれば調べてみてください。
第4の記号、=
の登場
そろそろ記号プログラミングの発想にも慣れてきたことと思います。
どんどん先に進んでいきましょう。そうしないと記事を書く私がもちません。
true
とfalse
を得る
[]+
の3種類の記号のみを用いて、真偽値型の値であるtrue
とfalse
を手に入れる方法は未だ発見されていません。
そのため、これらの値を手に入れるために新たな記号である=
を導入します。
ここで新たに記号を導入する最大の目的はboolキャストの手段を得るためですので、!
や<
、>
といった記号でも問題ありません。
!
は使い勝手が良いので人気のある記号ですが、今回は[]+
の3種類の記号で既に大半のプリミティブを得ているため、=
を採用します。
=
はなんといっても代入が解禁されるので魅力的な記号ですね。まあ記号だけでは変数名を書けないんですが。7
[]==[] // false
+[]==[] // true
// まわりくどい取り出し方をしているのは、
// []==[] (false) のあとに +[]を直接つなげると []==[]+[] (false) となって "false"が得られないため
[[[]==[]][0]+[]][0][3] // "s"
"constructor"
これで"true"
と"false"
に含まれる文字を手に入れることができました。
今までに得た文字を合わせると、"constructor"
という魔法の文字列が得られます。
[]["constructor"] // === Array
[]["constructor"]+[] // "function Array() { [native code] }"
""["constructor"]+[] // "function String() { [native code] }"
[]["find"]["constructor"] // Function ([]["constructor"]["constructor"]でもよい)
これでより多くの文字が得られ、さらにさまざまなコンストラクタにアクセスする方法も得ることができました。
関数呼び出しの壁と、あらゆるものを手に入れる力
()
の導入
関数を実行することができなければ、私たちにはわずかな力しかありません。
これまでJavaScriptを6種類よりも少ない記号の数で書こうとする試みはすべて、()
の記号なしには任意の関数を実行することができないというただ一点によって阻まれてきたのです。8
これまで6種類という限界を破ろうとした者の挑戦を悉く跳ね除け、そこに無数の屍の山を築き上げてきた()
の2文字を導入する時が来ました。
これで使用する記号の種類は[]()+=
の6種類となります。
Number.prototype.toString
()
の力を得て、さらに多くの文字を手に入れましょう。
const array = [];
for(let i=10;i<36;i++){
array.push(i.toString(36));
}
// array => ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"]
数値型の値の.toString()
メソッドに引数nを渡すと、その数値をn進数に変換した文字列が得られます。
たとえばx.toString(16)
でx
の16進数表記を得ることができます。
これによって、"a"
から"z"
までのすべての英小文字が表現可能です。
[20][0]["toString"](36) // "k"
関数の作成と実行
[]["find"]["constructor"]
はFunction
への参照を指しているので、これを実行することで関数を作成することができます。
[]["find"]["constructor"]("return 10") // function anonymous() {return 10}
[]["find"]["constructor"]("return eval")() // === eval
そしてeval
が手に入りました。
これで、文字列として表現したプログラムはすべて実行することができます。
遠すぎた"C"
とはいえ、まだすべての英大文字が手に入っているわけではなく、また様々な記号なども表現することができません。
我々に救いをもたらすと期待されている存在とは、即ちString.fromCharCode
です。
String.fromCharCode
は文字コードを数値で与えればそれに対応する文字を返すため、あらゆる文字が表現可能になります。9
しかしながら、現時点ではまだ"C"
は手に入っておらず、これを呼び出すことができません。10
"P"
の入手
const afunc = Function("return async "+Function())()
これを実行することでasync functionが得られます。
さらにasync functionの中身はPromiseですから、
afunc()+[] // "[object Promise]"
これで"P"
が得られました。
Object.getOwnPropertyNames
へのアクセス
[]["entries"]()["constructor"] // === Object
Object["getOwnPropertyNames"](String)["sort"]()[0] // "fromCharCode"
"P"
を得ることで何をするかというと、これで"getOwnPropertyNames"
を構築するための文字がすべて揃います。
Object
には上に示したように、Array.prototype.entries()
を実行して得られたイテレータの["constructor"]
がObject
と一致することを利用すればアクセスできます。
これによってString
が持っているメソッド名をすべて取得でき、当然"fromCharCode"
も"C"
の文字を得るより先に手に入ってしまいます。11
Theory of Everything
String["fromCharCode"](42) // "*"
String["fromCodePoint"](127843) // "🍣"
そういえばeval
を既に手に入れていましたね。
今や任意の文字列を構築可能なため、あらゆるJavaScriptコードが実行可能になりました。
例
たとえば、記事冒頭のプログラムは、console.log("Hello, World!")
と同じ処理を行っています。
これを記号化して実行するには、
eval('console.log("Hello, World!")')
少なくともこのようなプログラムが書ければ大丈夫ですね。
まあ実際には、console
さえ得られれば、メソッド呼び出し自体にはeval
を使用する必要がないので、
console.log("Hello, World!")
console["log"]("Hello, World!")
Function("return console")()["log"]("Hello, World!")
[]["find"]["constructor"]("return console")()["log"]("Hello, World!")
のように変形していけばよいです。eval
も不要ですね。
"!"
などの文字はString.fromCharCode()
を用いて生成することができるので、"Hello, World!"
の文字列は
String.fromCharCode(72) + // "H"
"e" + "l" + "l" + "o" +
String.fromCharCode(44) + // ","
" " +
String.fromCharCode(87) + // "W"
"o" + "r" + "l" + "d" +
String.fromCharCode(33) // "!"
のようにすれば構築できます。
同様にして[]["find"]["constructor"]("return console")()["log"]("Hello, World!")
の文字列部分をすべて記号で表現してしまえば、プログラムの記号化を行うことができ、最終的に記事冒頭のようなコードになります。12
まとめ・次回予告
この記事では、JavaScriptコードを最小限の記号だけで表現するための考え方について解説しました。
使用する記号の種類を少なくするためには、JavaScriptの暗黙の型変換やprototype
などについての仕様をうまく利用する必要があるので、記号プログラム化の手法について知ることはJavaScriptの言語仕様の理解をより深めることに繋がる……かもしれません。
今回は記号プログラムの基本的なアイデアや考え方に重点を置いているため、この記事で解説した事項は概ね既知のものです。13
https://github.com/aemkei/jsfuck 等で古くから行われている研究に対して、ここで改めて敬意を表します。
また、基本的な考え方は示しましたが、これだけで記号化したJavaScriptプログラムを書けるかと言われれば、まあ人間にとって無理があると考えざるを得ないでしょう。
やはりここは、JavaScriptコードを記号に変換するプログラムなどを作りたいところです。
この記事のタイトルには(1)というナンバリングがついていますので、もしかしたら次回があるかもしれません。14
現時点では何の見通しも進捗もありませんが、プログラムの記号化を行うプログラムの作成や、文字数節約のためのテクニックの紹介などは今回書けなかったので書きたいところです。
最終的なゴールとして、記号プログラムコンパイラを記号プログラムで書くとか、記号プログラムでクワインを書くといったあたりに到達できればと思っています。
続編 (2019/07/09追記)
記号プログラムコンパイラを記号プログラムで書きました。
第2回:記号プログラム変換器を作ろう
-
Xchars.js, aemkei/jsfuck また、提案段階の
|>
演算子が導入されれば5文字まで減らせることが明らかになっています (Xchars.js Subset: 5 characters) ↩ -
https://github.com/tc39/proposal-global, 👻globalThis👻と🌏global🌏と🌝this🌝 ↩
-
単に
++0
と書いても0
が右辺値となるのでインクリメントはできませんが、[0]
という配列の一要素に対してはインクリメントを行うことができます。a=[0];++a[0];
を実行する場合を考えましょう。 ↩ -
ある値
x
に対して、[x][0]
のように配列で包んで即座に中身を取り出すことで、()
の代わりに優先順位を明示することもできます。 たとえば0+0
をしようとして+[]++[]
と書いてしまうと++
の部分で構文エラーになりますが、+[]+[+[]][+[]]
と書くことで回避できます。 ↩ -
はじめての「意味のある文字列を添え字とした」プロパティアクセス ↩
-
主に表現の使いまわしによる文字数の節約に使えます。将来的に役に立つときが来る……予定です。 ↩
-
https://github.com/aemkei/jsfuck#execute-functions
toString
,valueOf
や``
などは、任意の引数を関数に与えることができないという点でうまくいかないとされています。 ↩ -
実際にはemojiなどの取得のために
String.fromCodePoint
も必要ですが ↩ -
実はhttps://github.com/aemkei/jsfuck/blob/87d4d4e9112e9c9a3dd7db34afcbbdc063b18a5b/jsfuck.js では、この時点で
"C"
を入手できています。それはFunction("return escape")()(("")["italics"]())[2]
を実行し、"<i></i>"
をescape
にかけるというものです。escape
関数は非推奨とされているので、ここではほかの方法をとることにしています。 ↩ -
ここでは「
String
の持つメソッド名をsortすると先頭に"fromCharCode"
が来る」という事実に依存しているため、将来的にメソッドが増えるなどして正しく取得できなくなる可能性があります。とはいえ、より良い取得方法に書き換えることは難しくありません。 ↩ -
冒頭のコードは横着して生成したので、実際にこの通りに記号化してもコードが一致しないことがあります。 ↩
-
ただし、
fromCharCode
を得るためのasync function
とgetOwnPropertyNames
の利用については、本記事の独自研究であると考えています。 ↩ -
というかもっともっと長い記事を書くつもりだったんですが、今回分だけで十分長くなってしまったので一度投稿した形となります ↩