JSRuby - Javascript による Ruby(っぽい)実装
- OreScript時代の幕開け - yukobaの日記
- http://d.hatena.ne.jp/yukoba/20071108/p1
巷で OreScript ブームが巻き起こる中、某所ではさらに局地的に Javascript での言語実装ブーム。
××さんが ******* を試作したり、西尾さんが python4js を試作したりして、うーむこんなおもしろそうなお祭りは看過できんでわないか。Ruby 成分の多い中谷としてはここはやっぱ Javascript で Ruby かっ!?
そういえばだれか Javascript でパーサ書いてはったよなあ。それを使わせてもらえば Ruby の構文木をさっくり得られて、ちょこちょこっとインタプリタ書いたら、FizzBuzz くらいなら動くんじゃないの? という思いついてしまったからには、もう作ってみるしか。
というわけで言った者勝ち(笑)の JSRuby をこしらえてみました。
リンク先のページで簡単な演算や FizzBuzz の実行テストを行えます。一応 IE6, Firefox2, Opera9, Safari3β で動作確認はしてみました。Safari2 では RegExp.rightContext がサポートされていないそうなので動きません(amachang サンクス)。すいません。
コードは <script type="text/ruby"> で埋め込んであるのを拾って textarea に出しているので、編集して実行することもできるようにしてあります。
んが、正直今のところ「 Ruby で書かれた FizzBuzz を実行できる、Ruby っぽい何か」なので、普通の Ruby スクリプトを入れてもまだまず動きません(苦笑)。
実装範囲は
・演算子 +, -, *, /, ==, ..
・演算の優先順位は有効
・数値、文字列リテラル
・代入
・組み込み関数 puts
・if ~ then ~ elsif ~ else ~ end
・配列に対する each メソッド
以上! って本当に FizzBuzz しか見てません……
とはいえ一応代入も if もちゃんと値を返すので、a=b=4 とか puts if x % 2 == 0 then "even" else "odd" end という書き方はちゃんとできます。
実装済みの範囲でも怪しいところはちらほら。特に前者はやばめ。
・パーサの時点で識別子をメソッドか変数か決定してしまっている(ミスった)
・Ruby の型を扱っていない(整数の割り算が実数になる、 .. 演算子が(javascriptの)配列を返す、など)
あと残念ながら、パーサは当初考えていた Gin ではなく、自前で再帰下降パーサを手書きしてます(隠れ左再帰を見つけられず、too much recursion を解消できなかった……)。
まあ半分ネタとはいえせっかく作ったので、上に書いた識別子の問題を解消し、ソースを分割、テストコードを付け、CodeRepos にアップさせてもらえれば、みんなでよってたかってつついてくれて、あれーいつの間にかできてる! とか妄想中w
フル実装は夢としても、どう書く?org の Rubyコードの7割がたが動く、くらいならかなり現実的な気もしますです。
この状態で使ってみようという人はいないと思いますが、簡単な使い方。
jsruby.js を組み込んで、
var parser = new RubyEngine.Parser(); var ruby = new RubyEngine.Interpreter(); ruby.run(parser.parse("puts 2*3+4*5; 9*9*9"))
とやれば指定の ruby コードを実行します。
ruby.run() の返値は最終の式の評価なので、この場合 729 が返ってきます。
また、標準出力の値は ruby.stdout から取り出せます(この場合 "26\n" が入っている)。
標準出力への書き出しは ruby.writeStdout() を上書きすることで変更できます。例えば ruby.run() の前に
ruby.writeStdout = function(st){ alert(st); }
と入れれば、都度ダイアログで表示されます。