Skip to content

Instantly share code, notes, and snippets.

@eterps
Created April 30, 2017 14:26
Show Gist options
  • Save eterps/d4cdd4d21a7651b3d3a4da6974faaaa1 to your computer and use it in GitHub Desktop.
Save eterps/d4cdd4d21a7651b3d3a4da6974faaaa1 to your computer and use it in GitHub Desktop.
gist of GoldenScheme.js
// License of this source is BSD License.
var GoldenScheme = function() {
// Get debug DOM
this.debugDom = document.getElementById("debug");
if (this.debugDom == null) {
this.debugDom = document.body;
}
// Firefox 莉・螟門ッセ遲�
if(typeof(console) == "undefined") {
console = {
log: function() {}
};
}
};
GoldenScheme.prototype = {
run: function(src) {
// 繝医�繧ッ繝翫う繧カ繝シ
var ary = src.match(/\(|\)|[^\(\)\t\r\n ]+/g);
// 讒区枚譛ィ菴懈�
var tree = [];
tree.vars = this.funcs;
this.parse(tree, ary, 1);
// 讒区枚譛ィ螳溯。�
var result = this.evalExpr(tree);
// 邨先棡陦ィ遉コ
this.printDebug(result);
},
parse: function(root, ary, pos) {
for(var i=pos; i<ary.length; i++) {
switch(ary[i]) {
case "(":
var aryChild = [];
aryChild.parent = root;
root.push(aryChild);
i = this.parse(aryChild, ary, i + 1);
break;
case ")":
return i;
default:
if(ary[i].match(/^-?[0-9]+$/)) {
root.push(parseInt(ary[i]));
} else {
root.push(this.createSymbol(ary[i], root));
}
}
}
},
createSymbol : function(name, parent) {
return {
type: "symbol",
name: name,
parent: parent
}
},
evalExpr: function(expr) {
// 繝励Μ繝溘ユ繧」繝門梛縺ェ繧峨�蛟、繧定ソ斐☆
if(!(typeof(expr) == "object")) {
return expr;
}
// 繧キ繝ウ繝懊Ν縺ョ蝣エ蜷医€∬ヲェ繧帝��ャ。謐懊@縺ヲ縺�¥
if(expr.type == "symbol") {
for(var f = expr; f != null; f = f.parent) {
if("vars" in f && expr.name in f.vars) {
console.log("[evalExpr] Eval symbol : " + expr.name);
return this.evalExpr(f.vars[expr.name]);
}
}
throw "[evalExpr] Cannot find symbol : " + expr.name;
}
// 縺薙%縺セ縺ァ譚・縺溘iS蠑�(驟榊�)縺ァ縺ェ縺�→縺�¢縺ェ縺�
if(!(expr instanceof Array)) {
throw "[evalExpr] Illegal type. Must be S-expression.";
}
// 迚ケ谿企未謨ー縺ッ荳ュ霄ォ繧定ゥ穂セ。縺励↑縺�
if(this.aryContains(this.lateEvalFunc, expr[0].name)) {
return this.funcs[expr[0].name].call(this, expr);
}
// 蠑墓焚繧定ゥ穂セ。
var ary = new Array(expr.length);
for(var i=0; i<expr.length; i++) {
ary[i] = this.evalExpr(expr[i]);
}
var execFunc = ary[0];
// 繝阪う繝�ぅ繝夜未謨ー縺ョ螳溯。�
if(typeof(execFunc) == "function") {
return execFunc.call(this, ary);
}
// lambda 縺ョ螳溯。�
if(execFunc instanceof Array && execFunc[0].name == "lambda") {
// 蜈��螟画焚繧剃ソ晏ュ�
var origVars = execFunc.vars;
// 螟画焚縺ョ蛻晄悄蛹�
execFunc.vars = {};
for(var i=1; i < ary.length; i++) {
execFunc.vars[execFunc[1][i - 1].name] = ary[i];
}
// 螳溯。�
var result = null;
for(var i=2; i<execFunc.length; i++) {
execFunc[i].parent = execFunc;
result = this.evalExpr(execFunc[i]);
}
// 蜈��螟画焚繧貞セゥ蜈�
execFunc.vars = origVars;
return result;
}
throw "[evalExpr] Cannot eval expr : " + expr;
},
aryContains: function(ary, nail) {
for(var i=0; i<ary.length; i++) {
if(ary[i] == nail) return true;
}
return false;
},
printDebug : function(str) {
var div = document.createElement("div");
var text = document.createTextNode(str);
div.appendChild(text);
this.debugDom.appendChild(div);
},
lateEvalFunc : ["quote", "define", "lambda", "if", "set!", "let"]
}
GoldenScheme.prototype.funcs = {
"begin" : function(ary) {
return ary[ary.length - 1];
},
"lambda" : function(ary) {
return ary;
},
"define" : function(ary) {
console.log("[define]");
for(var f = ary; f != null; f = f.parent) {
if(!("vars" in f)) continue;
if(ary[1].type == "symbol") {
console.log("[define] symbole name = " + ary[1].name);
f.vars[ary[1].name] = ary[2];
return ary[1].name;
} else if(ary[1] instanceof Array) {
// 逵∫払險俶ウ�
var arg = [];
for(var i=1; i < ary[1].length; i++) {
arg.push(ary[1][i]);
}
var f2 = [
{
type: "symbol",
name: "lambda"
},
arg,
ary[2]
];
f2[0].parent = f2;
f2.parent = ary;
f.vars[ary[1][0].name] = f2;
return ary[1][0].name;
} else {
throw "[define] Illegal arguments for define";
}
}
throw "[define] Cannot find vars";
},
"let" : function(ary) {
console.log("[let]");
// 螟画焚蜷阪→螟画焚縺ョ蛟、
var varNameList = [];
var varValueList = [];
for(var i=0; i < ary[1].length; i++) {
varNameList.push(ary[1][i][0]);
varValueList.push(ary[1][i][1]);
}
// 螟画焚縺ョ蛻晄悄蛹�
if(!("vars" in ary)) {
ary.vars = {};
}
for(var i=0; i<varNameList.length; i++) {
if(!(varNameList[i].name in ary.vars)) {
ary.vars[varNameList[i].name] = varValueList[i];
}
}
// 髢「謨ー縺ョ螳溯。�
var result;
for(var i=2; i<ary.length; i++) {
ary[i].parent = ary;
result = this.evalExpr(ary[i]);
}
return result;
},
"set!" : function(ary) {
console.log("[set!]");
for(var f = ary; f != null; f = f.parent) {
if("vars" in f && ary[1].type == "symbol" && ary[1].name in f.vars) {
f.vars[ary[1].name] = this.evalExpr(ary[2]);
console.log("[set!] name = " + ary[1].name + ", value = " + f.vars[ary[1].name]);
return ary[1].name;
}
}
throw "[set!] Illegal Argument";
},
"if" : function(ary) {
if(this.evalExpr(ary[1])) {
return this.evalExpr(ary[2]);
} else {
return this.evalExpr(ary[3]);
}
},
"cons" : function(ary) {
var cons = [ary[1], ary[2]];
cons.type = "cons";
return cons;
},
"quote" : function(ary) {
var quote = ary[1];
quote.type = "quote";
return quote;
},
"car" : function(ary) {
return ary[1][0];
},
"cdr" : function(ary) {
return ary[1][ary.length - 1];
},
"list" : function(ary) {
var top = [];
top.type = "cons";
var cons = top;
for(var i=1; i<ary.length; i++) {
cons.push(ary[i]);
if(i < ary.length - 1) {
var consNext = [];
consNext.type = "cons";
cons.push(consNext);
cons = consNext;
}
}
return top;
},
"+" : function(ary) {
var sum = 0;
for(var i=1; i < ary.length; i++) {
console.log("[+] ary[i] = " + ary[i]);
sum += ary[i];
}
console.log("[+] sum = " + sum);
return sum;
},
"-" : function(ary) {
if(ary.length == 1) return -ary[1];
var sum = ary[1];
for(var i=2; i < ary.length; i++) {
sum -= ary[i];
}
return sum;
},
"*" : function(ary) {
return ary[1] * ary[2];
},
"/" : function(ary) {
return ary[1] / ary[2];
},
"expt" : function(ary) {
return Math.pow(ary[1], ary[2]);
},
"=" : function(ary) {
return ary[1] == ary[2];
},
"<" : function(ary) {
return ary[1] < ary[2];
},
">" : function(ary) {
return ary[1] > ary[2];
},
"not" : function(ary) {
return !ary[1];
},
"display" : function(ary) {
this.printDebug(ary[1]);
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment