以前 manifest v2 な chrome extension では、eval や new Function() が禁止されると書いたが、なぜか new Function() は動いていた。しかし今日通しでテストしてみたらいよいよ動かなくなった。chrome のバージョンは 21.0.1180.89m だ。
wasavi では eval は除去してあるが、未だメッセージ中の特定の単語を付随する数字に従って変化させる処理と :s の置換文字列を生成する処理で new Function() を使っている。いずれも小規模な一種の言語といってよいものであり、コンパイルと実行処理が必要になるわけだが、実際にコンパイラと実行マシンを書くわけではなく javascript の機能でまかなっていた。
これらが今回動かなくなったので、書き換える。
まず前者。適当なメッセージ内の単語が数値に付随するとき、その数値によって単語が変化するパターンを得る。たとえば英語の場合、数値が 1 のときとそれ以外の場合に分けられる。そのためパターンは 2 種類必要になる。
従来、メッセージカタログ内に “n==1?’one’:”” というような javascript の式を置いていた。これを実行時に new Function() で関数に変換・保持し、実行時にメッセージを要求されたときに適宜使用する。今回、new Function() が使えなくなったので、自前で式を解析して評価する仕組みにしないといけない。
といっても javascript の式を解析する処理を書くわけにも行かないので、もっと単純な式にする。
変換識別子列 := 変換識別子
変換識別子 , 変換識別子列
変換識別子 := 変換関数名 ( 変換パターン接尾子 )
変換関数名 := [a-zA-Z_][a-zA-Z0-9_]*
変換パターン接尾子 := [a-zA-Z_][a-zA-Z0-9_]*
というような単純な式を動的に評価し、変換識別子の配列を持っておき、実行するようにした。メッセージカタログに置く式は “is_one(one)” といった形になる。is_one という変換関数の実態は wasavi.js に定義しなければならないので、従来の方法だと新たに言語に対応する際もメッセージカタログの新設で済んだのが、wasavi.js の対応も必要になることになる。
次に後者。これは例えば :s/foo\(bar\+\)/FOO\u\1/g みたいな ex コマンドが与えられたとき、置換文字列から “return ‘foo’ + arg[1].substring(0, 1).toUpperCase() + arg[1].substring(1);” みたいな javascript の式を生成し(arg は正規表現にマッチした結果の配列)、関数を作り出す処理。これも動かなくなるので、やはり適当な中間形式にコンパイルし実行させるようにしなければならない。こちらは、コンパイラと実行マシンを書く手間のほかに実行効率が気になる。なにしろ置換が発生するたびに呼ばれるのだ。しかしそう言ってもいられないので修正した。
* * *
最新のビルドをここで公開すると同時に、Chrome と Opera のエクステンションリポジトリに更新を申請した。