UNITCHECKと他復習
Perl5.10からBEGIN、CHECK、INIT、ENDの特別ブロックにUNITCHECKが追加されていたのを昨日知ったのでメモ。
あとそのほかまとめ復習。
perlmodにあったのを並び替えてみた。
#!/usr/bin/env perl # use 5.010; # begincheck BEGIN { print " 1. BEGIN blocks run FIFO during compilation.\n" } BEGIN { print " 2. So this line comes out second.\n" } UNITCHECK { print " 4. And therefore before any CHECK blocks.\n" } UNITCHECK { print " 3. UNITCHECK blocks run LIFO after each file is compiled.\n" } CHECK { print " 6. So this is the sixth line.\n" } CHECK { print " 5. CHECK blocks run LIFO after all compilation.\n" } INIT { print " 7. INIT blocks run FIFO just before runtime.\n" } INIT { print " 8. Run this again, using Perl's -c switch.\n" } INIT { print " 9. You'll see the difference right away.\n" } print "10. Ordinary code runs at runtime.\n"; print "11. It runs in order, of course.\n"; print "12. This is anti-obfuscated code.\n"; print "13. It merely _looks_ like it should be confusing.\n"; END { print "16. So this is the end of the tale.\n" } END { print "15. Read perlmod for the rest of the story.\n" } END { print "14. END blocks run LIFO at quitting time.\n" } __END__
名称 | 実行順序 |
---|---|
BEGIN | FIFO |
UNITCHECK | LIFO |
CHECK | LIFO |
INIT | FIFO |
END | LIFO |
FIFO…First in, First out…出てきたコードブロック順に実行
LIFO…Last in, First out…出てきたコードブロックの逆順に実行
UNITCHECKはBEGINとCHECKの間で実行される。
ただし、CHECKのように出てきたブロックを「あとで全部まとめて」実行するのではなくて、「package単位で」実行する。
挙動検証。
ついでに他のものも含めてやってみた。
useしたpackageのnoraml codeがCHECKよりも先にきている点が興味深い。
Hoge.pm
package Hoge; BEGIN { print "BEGIN [Hoge]\n" } UNITCHECK { print "2. UNITCHECK [Hoge]\n" } UNITCHECK { print "1. UNITCHECK [Hoge]\n" } CHECK { print "2. CHECK [Hoge]\n" } CHECK { print "1. CHECK [Hoge]\n" } INIT { print "INIT [Hoge]\n" } print "normal code [Hoge]\n"; END { print "2. END [Hoge]\n" } END { print "1. END [Hoge]\n" } 1;
Fuga.pm
package Fuga; BEGIN { print "BEGIN [Fuga]\n" } UNITCHECK { print "2. UNITCHECK [Fuga]\n" } UNITCHECK { print "1. UNITCHECK [Fuga]\n" } CHECK { print "2. CHECK [Fuga]\n" } CHECK { print "1. CHECK [Fuga]\n" } INIT { print "INIT [Fuga]\n" } print "normal code [Fuga]\n"; END { print "2. END [Fuga]\n" } END { print "1. END [Fuga]\n" } 1;
#!/usr/bin/env perl use Hoge; use Fuga; package main; BEGIN { print "BEGIN [main]\n" } UNITCHECK { print "2. UNITCHECK [main]\n" } UNITCHECK { print "1. UNITCHECK [main]\n" } CHECK { print "2. CHECK [main]\n" } CHECK { print "1. CHECK [main]\n" } INIT { print "INIT [main]\n" } print "normal code [main]\n"; END { print "2. END [main]\n" } END { print "1. END [main]\n" }
実行。
BEGIN [Hoge] # 1. UNITCHECK [Hoge] # use Hoge; 2. UNITCHECK [Hoge] # normal code [Hoge] # BEGIN [Fuga] # 1. UNITCHECK [Fuga] # use Fuga; 2. UNITCHECK [Fuga] # normal code [Fuga] # BEGIN [main] 1. UNITCHECK [main] 2. UNITCHECK [main] 1. CHECK [main] 2. CHECK [main] 1. CHECK [Fuga] 2. CHECK [Fuga] 1. CHECK [Hoge] 2. CHECK [Hoge] INIT [Hoge] INIT [Fuga] INIT [main] normal code [main] 1. END [main] 2. END [main] 1. END [Fuga] 2. END [Fuga] 1. END [Hoge] 2. END [Hoge]
BEGINとUNITCHECKがuseしたpackageごとに実行され、そのあとにCHECKを見つけた逆順に実行されている。
useしたpackageのUNITCHECK実行後に地の文(もとい地のコードか)が実行される。
まあ正直UNITCHECKをどう有効に使うのかまったくわかりませんけれども…!
コンパイルフェーズと実行フェーズ
構文解析とか字句解析とかするコンパイルフェーズと、実際にインタプリタで実行する実行フェーズはどう動くのか。
さっきのを-cオプションつけて実行してみるとコンパイルフェーズの実行結果だけ確認できる。
$ perl -c special_sub.pl BEGIN [Hoge] 1. UNITCHECK [Hoge] 2. UNITCHECK [Hoge] normal code [Hoge] BEGIN [Fuga] 1. UNITCHECK [Fuga] 2. UNITCHECK [Fuga] normal code [Fuga] BEGIN [main] 1. UNITCHECK [main] 2. UNITCHECK [main] 1. CHECK [main] 2. CHECK [main] 1. CHECK [Fuga] 2. CHECK [Fuga] 1. CHECK [Hoge] 2. CHECK [Hoge] special_sub.pl syntax OK
BEGIN、UNITCHECK、CHECKまでが実行される。(あとuseしたpackageの地の文も!)
逆に、出てこないINITは実行フェーズのブロックであることがわかる。
eval時
BEGINなどを含むコードをevalさせた時は、BEGINとUNITCHECKとENDしか実行されない。
BEGINは仕方ないにせよ、ENDがevalされたときは、ちゃんとそのプログラムのEND群にstackされる。
print "1. NORMAL CODE\n"; eval qq(BEGIN { print "begin\n" }); eval qq(UNITCHECK { print "unitcheck\n" }); eval qq(CHECK { print "check\n" }); eval qq(INIT { print "init\n" }); eval qq(END { print "end\n" }); print "2. NORMAL CODE\n"; END { print "END\n" }
1. NORMAL CODE begin unitcheck 2. NORMAL CODE end # <- ちゃんとENDになっている END