はじめに
ElixirでLispインタプリタを書きました。実用性はまったくありません。楽しいお遊びです。
使い方
mixで作ってあります。巻末のGithubからダウンロードあるいはクローンを作って mix lisp と入力すると起動します。
$ mix lisp
Compiling 1 file (.ex)
Lisp in Elixir
? (+ 1 2)
3
? (setq a 3)
3
?
処理系を終了するときは (quit)です。
仕様
ダイナミックスコープです。
使える特殊形式はdefunとsetq、quote,ifです。'がquoteの代わりになります。
defunでの暗黙のprognは使えません。
使える組み込み関数は下記の通りです。
+ - * / = > < >= <=
car cdr cons eq null atom numberp listp symbolp read eval print
プログラム構造、データ構造
4つのモジュールから成ります。Lisp、Read、Eval、Printのモジュールです。Lispには全体をとりまとめたREPLが収録されています。残りのモジュールはその名の通り、read,eval,printの各コードを収録しています。
readはS式を読み込みElixirのデータに変換して返します。そのデータの他に読み込み途中のバッファも返します。Tupleにして{sexp,buf}のようにしています。sexpは読み込んだものをElixirデータに変換したものです。リストであれば (+ 1 2) -> [:+,1,2] のようになります。bufは未読み込みのトークンのリストです。
evalはElixirのデータ型に変換されたs式を評価します。環境を常時、保持します。環境はキーワードリストの形式です。evalは評価した値をtupleにして{sexp,env}のようにして返します。
defunにより定義された関数は {:func,name,args,body} の形式のTupleになっています。これは環境に保持されます。
readのbuf,evalのenvはREPLループの間で保持されます。関数型のElixirでは大域変数を持ちません。このためbuf,envは引数として持ちまわるようにしてあります。
お気に召すまま
Elixirのコードは500行程度です。とてもシンプルです。あとはマクロを実装するなり、レキシカルスコープにするなり、M式対応にするなり、皆様、お気に召すまま改造してお楽しみください。BSDライセンスです。
ソースコード
ここに置いてあります。