Grassスクリプトを実行できる(?)LimeChatスクリプト「Grass.js」

本当に出来ているのかどうか怪しいんだけど,Grass処理系(?)をLimeChatスクリプトとして使えるようにしてみた.

function grass(code, inputHandler, outputHandler){
	// List
	function N(v, n) { this.n = n; this.v = v; }
	N.prototype.i = function(s) { var p = this; for(i = 1; i < s; ++i) p = p.n; return p; }
	N.prototype.s = function(v) { return new N(v, this); }
	var Eps = new N(null, null);
	function L(A) { var n = Eps; for(var i = A.length - 1; i >= 0; --i) n = new N(A[i], n); return n; }
	// Grass op-codes
	function App(m,n){ this.m = m; this.n = n; }
	function Abs(n,C){ this.n = n; this.c = C; }
	// Primitive functions
	function True(x){ return function(y) { return x; } }
	function False(x) { return function(y) { return y; } }
	function gW(c) { function w(s){ return s == w.w ? True : False; }; w.w = c; return w; }
	function Out(s) { if(!('w' in s)) throw new Error("文字じゃないくさいな(キリッ"); outputHandler(s.w); return s; }
	function In(s) { var c = inputHandler(); return c < 0 || c > 255 ? s : gW(c); }
	function Succ(s) { if(!('w' in s)) throw new Error("文字じゃないくさいな(キリッ"); s.w = (s.w+1)&255; return s; }

	// compile
	var tokens = code.replace(/[^WwvWwv]/g,'').match(/[ww]+|[WW]+[ww]+|[vv]/g) || [];
	var stateAbs = 0,stateApp = 1,state = stateAbs, C = [];
	while (tokens.length) {
		var tok = tokens.shift();
		if (tok.match(/^[ww]+/)) {
			if (state != stateAbs) throw new Error("文法エラーくさいな(キリッ");
			var nd = RegExp.lastMatch.length, Cd = [];
			for (;;) {
				if (!tokens.length || !tokens[0].match(/([WW]+)([ww]+)/)) break;
				tokens.shift();
				var m = RegExp.$1.length;
				var n = RegExp.$2.length;
				Cd.push(new App(m,n));
			}
			if (tokens.length && !tokens.shift().match(/^[vv]/)) throw new Error("文法エラーくさいな(キリッ");
			C.push(new Abs(nd,L(Cd)));
		} if (tok.match(/^([WW]+)([ww]+)/)) {
			if (state == stateAbs) state = stateApp;
			var m = RegExp.$1.length;
			var n = RegExp.$2.length;
			C.push(new App(m,n));
		}
	}
	var VM = { C: L(C), E: L([Out, Succ, gW(119), In]), D: L([[L([new App(1,1)]), Eps],[Eps, Eps]])};
	return function GrassStep() {
	// step
		if(VM.C != Eps || VM.D != Eps) {
			if (VM.C == Eps) {
				var f = VM.E.v;
				var d = VM.D.v;
				VM.C = d[0];
				VM.E = d[1].s(f);
				VM.D = VM.D.n;
			} else if (VM.C.v instanceof App) {
				var app = VM.C.v;
				var em = VM.E.i(app.m).v;
				var en = VM.E.i(app.n).v;
				if (!(em instanceof Array)) {
					// primitive function
					VM.E = VM.E.s(em(en));
					VM.C = VM.C.n;
				} else {
					// Grass function
					VM.D = VM.D.s([VM.C.n, VM.E]);
					VM.C = em[0];
					VM.E = new N(en, em[1]);
				}
			} else if (VM.C.v instanceof Abs) {
				var abs = VM.C.v;
				VM.E = VM.E.s([(abs.n > 1 ? L(new Abs(abs.n-1, abs.c)) : abs.c), VM.E]);
				VM.C = VM.C.n;
			}
			return GrassStep;
		} else {
			return null;
		}
	};
}

function event::onChannelText(prefix, channel, text) {
	if (text.match(/^grass>/)) {
		try {
			var output = "";
			var grassStep = grass(
				RegExp.rightContext, 
				function() { return -1; },
				function(c) { output += String.fromCharCode(c); }
			);
			var baseTime = new Date();
			(function GrassStepLoop() {
				if (new Date() - baseTime > 3000) {
					send(channel, "grass error : 時間掛かりすぎ。");
					send(channel, "grass output : " + output.substring(0, 64) + (output.length > 64 ? "..." : ""));
				} else {
					try {
						if (grassStep = grassStep()) {
							setTimeout(GrassStepLoop, 1);
						} else {
							send(channel, "grass output : " + output.substring(0, 64) + (output.length > 64 ? "..." : ""));
						}
					} catch (e) {
						send(channel, "grass error : "  + e.description);
					}
				}
			})();
		} catch (e) {
			send(channel, "grass error : "  + e.description);
		}
	}
}

grass>Grassスクリプト と発言すると,Grass VMが与えられたGrassスクリプトを実行し,出力された文字を表示する.実行に3秒以上掛かりそうだと,実行を中断して,そこまでに出力された文字とエラーメッセージを表示する.
誰得すぎるだろ,これは・・・