JavaScriptだけで動作するSCHEMEインタプリタ、SCHEMEON.js

ブラウザ上で動作するSCHEMEインタプリタを作ってみました!
InternetExplorer9、FirefoxChromeでざっと動作確認しています。
PCへのソフトのインストールは必要ありません。
次のURLにアクセスして、試してみてください。
SCHEMEON.js
[INPUT]欄に式を入力して[EVAL]ボタンを押せば、評価結果が[OUTPUT]欄に表示されます。それだけです。

SCHEMEとしての特徴(バージョン0.0120)

  • PCへのソフトのインストールが不要です。ブラウザだけで動作します。
  • JavaScriptライブラリに容易にアクセスすることができます。
  • SCHEMEとしてはR5RS準拠していますが、ファイル入出力関係の関数やマクロは実装していません。
  • 末尾再帰最適。
  • call/cc,values,call-with-valuesなどSCHEMEのトピックも実装しています。ちゃんと動くと思うけど…CO-RUTINEの例を使えばちゃんと動いてくれているか確認できるのかな。
  • 演算についてはJavaScriptそのままです。分数、正確数、不正確数などは実装していませんが、なるべく多くの演算子を実装しています。
  • ベンチマーク用にフィボナッチ関数、たらいまわし関数を初期化時に定義しています。ソースをご覧ください。

JavaScriptライブラリへのアクセス

JavaScriptオブジェクトとして、windowオブジェクトとdocumentオブジェクトが初めから使えます。
例えば次のように使います。

(window.alert "ABC")                        ; <- JavaScriptで window.alert("ABC");
(define s (document.getElementById "ABC"))  ; <- JavaScriptで var s = document.getElementById "ABC")

JavaScriptオブジェクトへのメンバーへのアクセスは obj.mmb1.mmb2 ... とします。

マインスイーパーで遊んでみよう!

ということで、マインスイーパーを作ってみました。
SCHEMEON.js : mine sweeper
すべての地雷を撤去できるかな?的な。
ソースを見ていただくと、何から何までSchemeで書いてあります。
Schemeでこういうの書いてみたかったんだよね!
リアルタイムでのブログエントリー→2012-07-12

テトリスで遊んでみましょう!

テトリスも動きますよ。
SCHEMEON.js :tetris
カーソルキーで移動、↑キーで回転です。
リアルタイムでのブログエントリー→2012-07-15

ブラウザのDOMオブジェクトの操作を実感できる例

もうひとつ例を用意してみました。使い勝手は少し悪いですが、HTML-DOMの操作をSCHEMEで行っていることがわかる例です。
次のURLにアクセスして、試してみてください。
SCHEMEON.js : DOM Emulation
[EVAL]ボタンが押されると、ウェブ上で表示されている次の式がそのまま評価されます。

(define r (document.getElementById "r"))
(define w (document.getElementById "w"))
(define in r.value)
(set! w.value (string-append in "\n->\n" (->string (eval (read-string in) (interaction-environment))) "\n----\n" w.value))
(set! r.value "")
(r.focus)

プログラムの通りですが、意訳すれば、次の通り実行されます。

ID="r"テキストエリア要素をrに束縛
ID="w"テキストエリア要素をrに束縛
"r"テキストエリアの文字列をinに束縛
in文字列を評価し、wテキストエリアに格納
"r"テキストエリアをクリア
"r"テキストエリアにフォーカス

他のJavaScriptライブラリを利用することもできます。

たとえば、Dateオブジェクトを利用したければ次のようにします。

(define Date (javascript "Date"))
(define now (new Date)) ;現在時刻を取得
(now.getYear) ;年を取得
(define d (new Date 2012 5 24)) ;2012/6/24を生成
(d.setMonth (+ (d.getMonth) 1)) ;2012/7/24に書き換え

JavaScript上からScheme式を評価する仕掛け

基本は次の通りです。

<SCRIPT type="text/javascript" src="http://ujip.ninja-web.net/schemeonjs/schemeon.js"></SCRIPT>
var v = scheme('SCHEME式');

この例では、文字列としてのSCHEME式を評価し、評価結果を文字列として返しています。
評価に時間のかかる処理(例えば、" (tarai 10 5 0)" など)を実行している時でもブラウザがハングアップしないような仕掛け(コールバック関数を用いる方法など)も用意していますが、それについては後日追記できればと思っています。ソース見ればわかるかも。

document.getElementById はパーザによって (jsref document "getElementById")に変換されます

document変数にはJavaScriptのdocumentオブジェクトが束縛されているんですね。
jsrefでは上の場合 document["getElementById"] の結果を返してくれます。

(document.getlementById "r")
 ↓
((jsref document "getElementById") "r")
 ↓
([JavaScriptのdocument.getElementById関数オブジェクト] "r") 

という具合に展開されます。
また、

a.b.c.d
  ↓パーザによって次のとおり展開
(jsref (jsref (jsref a "b") "c") "d") 

ということで、とにかくうまい塩梅に対応します。

とにかく試してみてください!!!

仕様、特にJavaScriptライブラリアクセス周りは後日、この日記に追記していければなぁと考えています。
たぶんバグはたくさんあります。日常生活に支障のない範囲で、少しずつ直していきたいです。
でもとにかく、JavaScript上でSchemeが動くんだなぁと思っていただければ幸いです。

作成したきっかけというか、思い

JavaScriptSCHEMEの影響を大きく受けています。
レキシカルクロージャなどすべてが第1級のオブジェクトである点であったり、名前空間が一つしかなかったり、SCHEMEを習得した人間なら見覚えのある考え方が、JavaScriptでは通用します。
JavaScriptはまた、現在最も多くの人々に実際に使用されている、生活に根差した言語です。
ブラウザ上のあらゆるオブジェクトを操作するため関係するライブラリは充実していますし、AJAX技術の登場はJavaScriptの底力を見せつけてくれました。
Windowsでも Windows Scripting Host の一言語として活躍しています。
そしてなんと言っても、JavaScriptは最速のインタプリタといっても過言ではありません。
ブラウザのJavaScriptだけでシューティングゲームが作成される世の中です。
携帯ゲーム機のエミュレータさえJavaScriptで記述される時代です。
すでに言い尽くされた言葉かもしれませんが、JavaScriptブラウジングの基盤、プラットホームであります。

そんなJavaScriptプラットホーム上の様々なライブラリを、SCHEMEで使ってみたいと思ったことはありませんか?

SCHEMEでブラウザ操作スクリプトが書けたら。
Windows Scripting HostでWindowsが操作できたら。
なんか面白いんじゃないかって思ったことはありませんか?
私は少しそんな妄想を抱きました。
そこで、SCHEMEからJavaScriptのライブラリにアクセスできる、JavaScriptだけで記述されSCHEMEインタプリタを作ってみようかなぁと思った次第です。

以上いろいろ本当に書きかけですが

とりあえず公開してみました。
このエントリーを少しずつ修正して、ちまちまやっていきたいと思います。
正直、このSCHEMEON.jsに需要があるとは思っていません!

履歴

  • 2012.08.18 syntax-rules,define-syntax,let-syntax,letrec-syntax実装。HTML内のscriptタグ内にSchemeソースの記述ができるようにした。
  • 2012.07.15 テトリスを公開。
  • 2012.07.12 マインスイーパーを公開。他にもしょうもない不具合修正。一通り使えるようになった。
  • 2012.07.08 evalを導入。
  • 2012.07.01 伝統的マクロを導入。
  • 2012.06.30 do文のバグ修正。
  • 2012.06.28 バグ修正、caar〜cddddrを入れてみた。
  • 2012.06.23 公開。