diff interp.js @ 208:a1b4a2bc8d72

Initial work on pattern match macrosfor the new parser
author Mike Pavone <pavone@retrodev.com>
date Fri, 22 Nov 2013 19:37:25 -0800
parents 60eff5f81d9a
children 4b3b57f39f10
line wrap: on
line diff
--- a/interp.js	Tue Nov 19 22:02:11 2013 -0800
+++ b/interp.js	Fri Nov 22 19:37:25 2013 -0800
@@ -25,6 +25,9 @@
 Number.prototype['tpmeth_<='] = function(other) {
 	return this <= other ? tptrue : tpfalse;
 };
+Number.prototype.tpmeth_asStringChar = function() {
+	return String.fromCharCode(this);
+};
 Number.prototype.tpmeth_string = function() {
 	return '' + this;
 };
@@ -38,9 +41,33 @@
 String.prototype['tpmeth_='] = function(other) {
 	return this == other ? tptrue : tpfalse;
 };
+String.prototype.tpmeth_length = function() {
+	return this.length;
+};
+String.prototype.tpmeth_byte_length = function() {
+	return this.length;
+};
+String.prototype.tpmeth_byte = function(index) {
+	return this.charCodeAt(index);
+};
+String.prototype['tpmeth_from:withLength'] = function(pos, length) {
+	return this.substr(pos, length);
+};
 String.prototype.tpmeth_print = function() {
 	print(this);
-}
+};
+
+Function.prototype['tpmeth_while:do'] = function(body) {
+	var ret = null;
+	for (;;) {
+		var res = this.call(null);
+		if (res != tptrue) {
+			break;
+		}
+		ret = body.call(null);
+	}
+	return ret;
+};
 
 var tptrue = null;
 var tpfalse = null;
@@ -93,6 +120,9 @@
 	findMacro: function(name) {
 		return null;
 	},
+	findQuoteTrans: function(name) {
+		return null;
+	}
 }
 
 function environment(parent)
@@ -100,6 +130,7 @@
 	this.parent = parent;
 	this.syms = {};
 	this.macros = {};
+	this.quotetrans = {};
 }
 
 environment.prototype = {
@@ -150,6 +181,15 @@
 		}
 		return null;
 	},
+	findQuoteTrans: function(name) {
+		if (name in this.quotetrans) {
+			return this.quotetrans[name];
+		}
+		if (this.parent) {
+			return this.parent.findQuoteTrans(name);
+		}
+		return null;
+	},
 	defMacro: function(name, def) {
 		this.syms[name] = def;
 		this.macros[name] = true;
@@ -162,7 +202,7 @@
 		return new intlit(val);
 	}
 	if (typeof val == 'string') {
-		return new stringlit(val);
+		return new strlit(val);
 	}
 	if (val instanceof Array) {
 		return new arraylit(val);
@@ -196,8 +236,30 @@
 	return this;
 };
 
+op.prototype.quote = function(env) {
+	var left = this.left.quote(env);
+	var right = this.right.quote(env);
+	return new op(left, this.op, right);
+};
+
+var quote_prefix = 0;
+
 symbol.prototype.eval = function(env) {
-	return env.find(this.name);
+	var res = env.find(this.name);
+	if (res === null) {
+		throw new Error('Symbol ' + this.name + ' is not bound');
+	}
+	return res;
+};
+
+symbol.prototype.quote = function(env) {
+	var val = env.find(this.name);
+	if (val) {
+		return makeASTNode(val);
+	} else {
+		var hygenic = env.findQuoteTrans(this.name);
+		return hygenic ? new symbol(hygenic, this.symbols) : this;
+	}
 };
 
 intlit.prototype.eval =
@@ -216,6 +278,14 @@
 	return this;
 };
 
+intlit.prototype.quote =
+	floatlit.prototype.quote =
+	strlit.prototype.quote =
+	arraylit.prototype.quote =
+	listlit.prototype.quote = function(env) {
+	return this;
+};
+
 funcall.prototype.eval = function(env) {
 	var args = [];
 	var name = this.name;
@@ -224,10 +294,10 @@
 	}
 	if (name == 'quote') {
 		if (this.receiver) {
-			return this.receiver;
+			return this.receiver.quote(env);
 		}
 		if (this.args.length) {
-			return this.args[0];
+			return this.args[0].quote(env);
 		}
 		throw new Error('quote takes an argument');
 	}
@@ -253,11 +323,11 @@
 		return fun.apply(null, args);
 	} else {
 		//if (typeof args[0]'tpmeth_'+name in args[0]) {
-			//try {
+			try {
 				return args[0]['tpmeth_'+name].apply(args[0], args.slice(1));
-			/*} catch(e) {
-				throw new Error('Error, \n\t' + e.message.split('\n').join('\n\t') + '\ninvoking method ' + name + ' on object ' + args[0] + ' ' + JSON.stringify(Object.keys(args[0])));
-			}*/
+			} catch(e) {
+				throw new Error('Error, \n\t' + e.message.split('\n').join('\n\t') + '\ninvoking method ' + name + ' on object ' + args[0]);
+			}
 		/*} else {JSON.stringify
 			throw new Error('No method named ' + name + ' on object ' + JSON.stringify(args[0]));
 		}*/
@@ -289,6 +359,21 @@
 	return makeASTNode(macro.apply(null, args));
 };
 
+funcall.prototype.quote = function(env) {
+	var receiver = this.receiver ? this.receiver.quote(env) : null;
+	var args = [];
+	for (var i = 0; i < this.args.length; i++) {
+		args.push(this.args[i].quote(env));
+	}
+	var name = env.findQuoteTrans(this.name);
+	if (!name) {
+		name = this.name;
+	}
+	var ret = new funcall(name, args);
+	ret.receiver = receiver;
+	return ret;
+};
+
 object.prototype.eval = function(parentenv) {
 	var env = new environment(parentenv);
 	var obj = {env: env};
@@ -369,6 +454,32 @@
 	return this;
 };
 
+object.prototype.quote = function(parentenv) {
+	var env = new environment(parentenv);
+	var outmessages = [];
+	for (var i = 0; i < this.messages.length; i++) {
+		var msg = this.messages[i];
+		if (msg instanceof assignment) {
+			//Make sure method names don't get renamed for hygene
+			env.syms[msg.symbol.name] = null;
+			env.quotetrans[msg.symbol.name] = msg.symbol.name;
+			if (msg.expression instanceof lambda) {
+				env.syms[msg.symbol.name + '!'] = null;
+				env.quotetrans[msg.symbol.name + '!'] = msg.symbol.name + '!';
+			}
+		}
+	}
+	for (var i = 0; i < this.messages.length; i++) {
+		var msg = this.messages[i];
+		if (msg instanceof assignment) {
+			outmessages.push(new assignment(msg.symbol, msg.expression.quote(env)));
+		} else {
+			outmessages.push(msg.quote(env));
+		}
+	}
+	return new object(outmessages);
+};
+
 lambda.prototype.eval = function(parentenv) {
 	var args = this.args;
 	var exprs = this.expressions;
@@ -380,7 +491,7 @@
 			}
 			env.syms[args[j].cleanName()] = arguments[i];
 		}
-		if (this != null && (args.length == 0 || args[0].cleanName() != 'self')) {
+		if (this != null && !(args.length == 0 || args[0].cleanName() != 'self')) {
 			env.syms['self'] = this;
 		}
 		var res = null;
@@ -412,6 +523,22 @@
 	return this;
 };
 
+lambda.prototype.quote = function(parentenv) {
+	var args = [];
+	var expressions = [];
+	var env = new environment(parentenv);
+	for (var i = 0; i < this.args.length; i++) {
+		env.syms[this.args[i].cleanName()] = null;
+		var hygenic = '' + quote_prefix + this.args[i].cleanName();
+		env.quotetrans[this.args[i].cleanName()] = hygenic;
+		args.push(new symbol(hygenic, this.args[i].symbols));
+	}
+	for (var i = 0; i < this.expressions.length; i++) {
+		expressions.push(this.expressions[i].quote(env));
+	}
+	return new lambda(args, expressions);
+};
+
 assignment.prototype.eval = function(env) {
 	var val = this.expression.eval(env);
 	env.findSet(this.symbol.name, val);
@@ -422,3 +549,11 @@
 	this.expression = this.expression.macroexpand(env);
 	return this;
 };
+
+assignment.prototype.quote = function(env) {
+	var name = this.symbol.cleanName();
+	env.syms[name] = null;
+	var hygenic = '' + quote_prefix + name;
+	env.quotetrans[name] = hygenic;
+	return new assignment(new symbol(hygenic, this.symbol.symbols), this.expression.quote(env));
+};