JavaScriptでおもちゃのLispを作ろう(5)〜組込み関数編〜

前回までに組込み関数を一切定義していないピュアなLisp処理系ができました。今回は必要最小限の組込み関数を実装します。

/*
 * 関数に名前をつけて登録する。引数lazyがtrueのときは、関数の引数を評価しない。
 * スペシャルフォームのときtrueをセットするようにする。
 */
function define(name, func, lazy) {
  var proc = new Procedure(name, func, lazy);
  var sym = intern(name);
  sym.value = proc;
}

function progn(exp) {
  var rv = NIL;
  for (var p = exp; !atom(p); p = cdr(p)) {
    rv = eval(car(p));
  }
  return rv;
}

function append(x, y) {
  if (x === NIL) {
    return y;
  } else {
    return cons(car(x), append(cdr(x), y));
  }
}

define("quote",  function (x) { return x; }, true);
define("lambda", function (x) { return cons(LAMBDA, x); }, true);
define("cons",   function (x) { return cons(car(x), cadr(x)); });
define("car",    function (x) { return caar(x); });
define("cdr",    function (x) { return cdar(x); });
define("caar",   function (x) { return caar(car(x)); });
define("cadr",   function (x) { return cadr(car(x)); });
define("cdar",   function (x) { return cdar(car(x)); });
define("cddr",   function (x) { return cddr(car(x)); });
define("null",   function (x) { return (car(x) === NIL) ? T : NIL; });
define("eq",     function (x) { return (car(x) === cadr(x)) ? T : NIL; });
define("equal",  function (x) { return equal(car(x), cadr(x)) ? T : NIL; });
define("list",   function (x) { return x; });
define("progn",  function (x) { return progn(x); }, true);
define("append", function (x) { return append(car(x), cadr(x)); });

condなどの制御文に相当するものも同様に実装できます。

define("cond", function (x) {
  for (var p = x; !atom(p); p = cdr(p)) {
    var v = eval(caar(p));
    if (v !== NIL) {
      return (cdar(p) === NIL) ? v : progn(cdar(p));
    }
  }
  return NIL;
}, true);

define("setq", function (x) {
  var v = NIL;
  for (var sym = x, val = cdr(x); !atom(sym); sym = cddr(sym), val = cddr(val)) {
    v = setValue(car(sym), eval(car(val)));
  }
  return v;
}, true);

define("defun", function (x) {
  var sym = intern(car(x));
  sym.value = cons(LAMBDA, cdr(x));
  return sym;
}, true);


これまで、動作確認は端末ベースでJavaScriptが実行できるSpiderMonkeyRhinoのエンジンを使っていましたが、次回はブラウザ上で実行するための対話環境を実装します。ブラウザ上で動作するようになったら、逐次、全ソースを公開していく予定です。