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秒以上掛かりそうだと,実行を中断して,そこまでに出力された文字とエラーメッセージを表示する.
誰得すぎるだろ,これは・・・