consを利用した言語の実装

とりあえず、四則演算+if文が使えるxxx言語を実装してみました。javascriptで。

[if, [=,[+,1,2],4],111, 222]
if[=[+[1,2],4],111,222]
if (=[+[1,2],4]) [111,222]
if (= (+[ 1, 2]) 4 []) 111 222 []
if (= (+ 1 2 []) 4 []) 111 222 []
(if (= (+ 1 2 []) 4 []) 111 222 [])

これらは全て同じ意味で、
JavaScriptやらC言語だと

(1+2 == 4) ? 111 : 222

Lispだと

(if (= (+ 1 2) 4) 111 222)

の意味になります。いちお、Lispとは違う式指向言語になっております。
こういった言語が他にないのか知りたいところです。
どっかにあっていいと思うのだけど。

追記

最終的に変換してくると、S式にとても似ている。

(if (= (+ 1 2 []) 4 []) 111 222 [])
(if (= (+ 1 2) 4) 111 222)

が同じ意味となるようにしたら、S式の自然な拡張にできて、
いいのではないかという風に思います。


さらに追記&修正


[]は;であるとする。するとすると、、、。

if (= (+ 1 2;) 4;) 111 222;
if (=[+[1,2],4]) 111 222;

なんて書けて、

[if, [=,[+,1,2],4],111, 222]
if[=[+[1,2],4],111,222]
if (=[+[1,2],4]) [111,222]
if (= (+[ 1, 2]) 4 []) 111 222 []
if (= (+ 1 2 []) 4 []) 111 222 []
(if (= (+ 1 2 []) 4 []) 111 222 [])
(if (= (+ 1 2 ;) 4 ;) 111 222 ;)
if (= (+ 1 2;) 4;) 111 222;
if (=[+[1,2],4]) 111 222;

と言った具合になるぞと。おお、凄いかもしれないし、凄くないかもしれない。


以下ソース

<script>
var nil = [null, null];
function sexp(str) {
	var pop = function() {
		str = str.replace(/^ +/,"");
		var s = str.charAt(0);
		str = str.substring(1);
		return s;
	};
	var peek = function() {
		str = str.replace(/^ +/,"");
		return str.charAt(0);
	};
	var cons = function() {
		document.write("cons "+str+"<br>");
		var c = atom();
		if (peek() != "." && peek() != "" && peek() != "," && peek() != "]"&& peek() != ")") {
			c = [c, cons()];
		}
		document.write("ret cons "+c+"<br>");
		return c;
	}

	var atom = function() {
		document.write("atom "+str+"<br>");
		var c = peek();
		if (c == ";") {
			pop();
			return [null,null];
		}
		if (c == "(") {
			pop();
			c = cons();
			if (pop() != ")") throw "error ] ... ["+str+"]";
			return c;
		}
		if (c == "[") {
			pop();
			c = paren();
			if (pop() != "]") throw "error ] ... ["+str+"]";
			return c;
		}
		if (c == "\"") {
			var s = str.match(/^"[^"]+"/);
			return s.substring(1, s.length - 1);
		}
		if (c.match(/^[0-9]/)) {
			var s = str.match(/^[0-9]+/);
			str = str.substring(s[0].length);
			return Number(s[0]);
		}
		if (c.match(/^[^\r\n\t\:\, ]/)) {
			var s = str.match(/^[^\r\n\t\]\[\:\,\(\) ]+/);
			document.write(str+"<br>");
			str = str.substring(s[0].length);
			document.write(">"+str+"<br>");
			if (s[0] == "NIL") return nil;
			return s[0];
		}
//		document.write("["+c + "]...[" + str + "]<br>");
		throw "error atom" + str;
	}
	var paren = function() {
//		document.write("paren "+str+"<br>");
		if(peek() == "]") return [null, null];
		var c = cons();
		if (peek() == "]") return [c, [null,null]];
		if (peek() == "...") { pop(); return [c, cons()]; }
		if (peek() == ",") { pop(); return [c, paren()]; }
		return c;
	};
	return cons();
}

//try{
//	alert(sexp("(12 13)"));
//} catch (e) {alert(e);}

function isNil(l) {
	return (l[0] == null) && (l[1] == null);
}

// リスト表示
function p2(e) {
	var s1 = "";
	if (e[0] instanceof Array) {
		s1 = p(e[0]);
	} else {
		s1 = e[0] + "";
	}
	if (e[1] instanceof Array) {
		if (isNil(e[1])) return s1;
		return s1 + " " + p2(e[1]);
	}
	return s1 + " . "+ e[1];
}
function p(e) {
	aaaacnt++;
	if(aaaacnt > 100) return " ... overflow ...";
	if (e instanceof Array) {
		if (isNil(e)) return "nil";
		return "("+p2(e)+")";
	}
	return "" + e;
}

//alert(p([[1,2],[1,nil]]));

Array.prototype.toString = function() {
	aaaacnt = 0;
	return p(this);
}
// Arrayをリストに変換する。
// [1, 2, 3] -> [1 ,[2, [3, nil]]]
function list(a) {
	if (typeof(a) == "object" && a.length != null) {
		var r = nil;
		if (a.length  >= 3 && a[a.length - 2] == ".") {
			r = [a[a.length - 3], a[a.length - 1]];
			a.length -= 3;
		}
		for (var i = a.length - 1; i >= 0; i--)
			r = [list(a[i]), r];
		return r;
	}
	return a;
};
var car = function (r) { return r[0]; };
var cdr = function (r) { return r[1]; };
var cons = function (a, b) { return [a, b]; };
var replcar = function (a, b) {
	a[0] = b;
	return a;
};
function caar(l) { return car(car(l)); }
function cadr(l) { return car(cdr(l)); }
function cdar(l) { return cdr(car(l)); }
function cddr(l) { return cdr(cdr(l)); }
function caddr(l)   { return car(cdr(cdr(l))); }
function cadddr(l)  { return car(cdr(cdr(cdr(l)))); }
function caddddr(l) { return car(cdr(cdr(cdr(cdr(l))))); }

function eval(p, env) {
	if (!isNaN(p))return p;
	if (p instanceof Array) {// 関数適用
		switch (car(p)) {
		case "+": return eval(cadr(p), env) +  eval(caddr(p), env);
		case "-": return eval(cadr(p), env) -  eval(caddr(p), env);
		case "*": return eval(cadr(p), env) *  eval(caddr(p), env);
		case "/": return eval(cadr(p), env) /  eval(caddr(p), env);
		case "=": return eval(cadr(p), env) == eval(caddr(p), env);
		case "if": return eval(cadr(p), env) ? eval(caddr(p), env) : eval(cadddr(p), env);
		}
		var envs = getEnv(p[0], env);
		return eval(e, envs[1]);
	}
	var envs = getEnv(p, env);
	return eval(envs[0], envs[1]);
}
function getEnv(p, env) {
	while (env != null) {
		if (env[p] != null)
			return [env[p], env];
		env = env["parent"];
	}
}
//alert(eval(sexp("(if (= (+ 1 2) 4) 111 222)")));
alert(eval(sexp("[if, [=,[+,1,2],4],111, 222]")));
alert(eval(sexp("if[=[+[1,2],4],111,222]")));
alert(eval(sexp("if (=[+[1,2],4]) [111,222]")));
alert(eval(sexp("if (= (+[ 1, 2]) 4 []) 111 222 []")));
alert(eval(sexp("if (= (+ 1 2 []) 4 []) 111 222 []")));
alert(eval(sexp("(if (= (+ 1 2 []) 4 []) 111 222 [])")));
alert(eval(sexp("if (= (+ 1 2;) 4;) 111 222;")));
alert(eval(sexp("if (=[+[1,2],4]) 111 222;")));
</script>