Shogo's Blog

たぶんプログラミングとかについて書いていくブログ

PerlとGolangで実行できるPolyglot書いてみた

Rubyの会社をPerlの会社に変えてしまおう計画。 Golangのフリをして忍び込ませれば行けるのではという話になったので、 GoでもPerlでも実行できるコードを書いてみた。

出来上がったのがこちら。

1
2
3
4
5
6
7
8
package main;
import ("fmt");
var (s=0/*==);
sub import {}
sub var { print "Hello macotasu"; }
__END__
*/)
func main() { fmt.Println("Hello macotasu") }

一番のポイントはvar (s=0/*==);の行ですね。 Perlで解釈すると正規表現置換s///として解釈され、/*が無視されます。 Goで解釈すると変数sへの代入として解釈され、/*がコメントとして扱われます。

あとはGoのキーワードをPerlが解釈できないので、ちょっと書き方を工夫します。

  • package main はGoでもPerlでも似たような意味で解釈されるのでそのまま
  • Goの import, var はPerlで解釈できないので、()を省略せずに書いてPerlの関数呼び出しっぽくする
  • 省略可能なセミコロンをちゃんと書く

GoとPerlのコードは分かれているのでどんな処理でも自由に書くことができますが、 import だけGoでもPerlでも解釈されてしまうというという制限があります。 import するパッケージが一個だけなら問題ないんですが、 複数書く場合は以下のように2個め以降をすべてドットインポートする必要があって男気あふれる感じです。 (Perlでは文字列結合として解釈される。Goではvarのあとにimportかけないっぽいので、ここに押し込むしかない。)

1
2
3
4
5
6
7
8
9
10
11
package main;
import (
  "fmt"
  . "math"
);
var (s=0/*==);
sub import {}
sub var { print "Hello macotasu"; }
__END__
*/)
func main() { fmt.Println("Hello macotasu", Pi) }

もっと簡潔にかけないかな。

追記

シンタックスハイライトしてみたらわかりやすいかなと思ってやってみた。

Perlのシンタックスハイライト。

1
2
3
4
5
6
7
8
package main;
import ("fmt");
var (s=0/*==);
sub import {}
sub var { print "Hello macotasu"; }
__END__
*/)
func main() { fmt.Println("Hello macotasu") }

Goのシンタックスハイライト。

1
2
3
4
5
6
7
8
package main;
import ("fmt");
var (s=0/*==);
sub import {}
sub var { print "Hello macotasu"; }
__END__
*/)
func main() { fmt.Println("Hello macotasu") }

参考

Comments