changeset 209:4b3b57f39f10

Implement zeroPlus macro
author Michael Pavone <pavone@retrodev.com>
date Wed, 27 Nov 2013 23:36:24 -0800
parents a1b4a2bc8d72
children d0848563f25d
files interp.js modules/parser.tp
diffstat 2 files changed, 167 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/interp.js	Fri Nov 22 19:37:25 2013 -0800
+++ b/interp.js	Wed Nov 27 23:36:24 2013 -0800
@@ -28,6 +28,9 @@
 Number.prototype.tpmeth_asStringChar = function() {
 	return String.fromCharCode(this);
 };
+Number.prototype['tpmeth_isString?'] = function() {
+	return false;
+};
 Number.prototype.tpmeth_string = function() {
 	return '' + this;
 };
@@ -53,6 +56,9 @@
 String.prototype['tpmeth_from:withLength'] = function(pos, length) {
 	return this.substr(pos, length);
 };
+String.prototype['tpmeth_isString?'] = function() {
+	return true;
+};
 String.prototype.tpmeth_print = function() {
 	print(this);
 };
@@ -218,13 +224,22 @@
 
 op.prototype.eval = function(env) {
 	var l = this.left.eval(env);
-	var r = this.right.eval(env);
 	var name = this.op;
+	if (name == '&&' || name == '||') {
+		var r = (new lambda([], [this.right])).eval(env);
+	} else {
+		var r = this.right.eval(env);
+	}
 	var fun = env.findNoTop(name);
 	var ret;
 	if (fun) {
 		ret = fun(l,r)
 	} else {
+		if (name == '&&') {
+			name = 'if'
+		} else if (name == '||') {
+			name = 'ifnot'
+		}
 		ret = l['tpmeth_'+name](r);
 	}
 	return ret;
@@ -242,6 +257,22 @@
 	return new op(left, this.op, right);
 };
 
+op.prototype.tpmeth_nodeType = function() {
+	return "op";
+};
+
+op.prototype.tpmeth_left = function() {
+	return this.left;
+};
+
+op.prototype.tpmeth_right = function() {
+	return this.right;
+};
+
+op.prototype.tpmeth_opName = function() {
+	return this.op;
+};
+
 var quote_prefix = 0;
 
 symbol.prototype.eval = function(env) {
@@ -255,13 +286,25 @@
 symbol.prototype.quote = function(env) {
 	var val = env.find(this.name);
 	if (val) {
-		return makeASTNode(val);
+		var newnode = makeASTNode(val);
+		if (!(newnode instanceof symbol)) {
+			newnode = newnode.quote(env);
+		}
+		return newnode;
 	} else {
 		var hygenic = env.findQuoteTrans(this.name);
 		return hygenic ? new symbol(hygenic, this.symbols) : this;
 	}
 };
 
+symbol.prototype.tpmeth_nodeType = function() {
+	return "symbol";
+};
+
+symbol.prototype.tpmeth_name = function() {
+	return this.cleanName();
+};
+
 intlit.prototype.eval =
 	floatlit.prototype.eval =
 	strlit.prototype.eval =
@@ -286,6 +329,34 @@
 	return this;
 };
 
+intlit.prototype.tpmeth_nodeType = function() {
+	return "intlit";
+};
+
+floatlit.prototype.tpmeth_nodeType = function() {
+	return "floatlit";
+};
+
+strlit.prototype.tpmeth_nodeType = function() {
+	return "strlit";
+};
+
+arraylit.prototype.tpmeth_nodeType = function() {
+	return "arraylit";
+};
+
+listlit.prototype.tpmeth_nodeType = function() {
+	return "strlit";
+};
+
+intlit.prototype.tpmeth_value =
+	floatlit.prototype.tpmeth_value =
+	strlit.prototype.tpmeth_value =
+	arraylit.prototype.tpmeth_value =
+	listlit.prototype.tpmeth_value = function() {
+	return this.val;
+}
+
 funcall.prototype.eval = function(env) {
 	var args = [];
 	var name = this.name;
@@ -297,6 +368,7 @@
 			return this.receiver.quote(env);
 		}
 		if (this.args.length) {
+			var cur = env;
 			return this.args[0].quote(env);
 		}
 		throw new Error('quote takes an argument');
@@ -365,15 +437,33 @@
 	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 name = this.name;
+	if (name[name.length-1] == ":") {
+		name = name.substr(0, name.length-1);
+	}
+	var fun = env.find(name);
+	if (fun) {
+		fun = makeASTNode(fun);
+		if (fun instanceof symbol) {
+			name = fun.cleanName();
+		} else if (fun instanceof lambda) {
+			throw new Error('FIXME');
+		}
+	} else {
+		var hygenic = env.findQuoteTrans(this.name);
+		if (hygenic) {
+			name = hygenic;
+		}
 	}
 	var ret = new funcall(name, args);
 	ret.receiver = receiver;
 	return ret;
 };
 
+funcall.prototype.tpmeth_nodeType = function() {
+	return "funcall";
+};
+
 object.prototype.eval = function(parentenv) {
 	var env = new environment(parentenv);
 	var obj = {env: env};
@@ -480,6 +570,10 @@
 	return new object(outmessages);
 };
 
+object.prototype.tpmeth_nodeType = function() {
+	return "object";
+};
+
 lambda.prototype.eval = function(parentenv) {
 	var args = this.args;
 	var exprs = this.expressions;
@@ -539,6 +633,10 @@
 	return new lambda(args, expressions);
 };
 
+lambda.prototype.tpmeth_nodeType = function() {
+	return "lambda";
+};
+
 assignment.prototype.eval = function(env) {
 	var val = this.expression.eval(env);
 	env.findSet(this.symbol.name, val);
@@ -557,3 +655,7 @@
 	env.quotetrans[name] = hygenic;
 	return new assignment(new symbol(hygenic, this.symbol.symbols), this.expression.quote(env));
 };
+
+assignment.prototype.tpmeth_nodeType = function() {
+	return "assignment";
+};
--- a/modules/parser.tp	Fri Nov 22 19:37:25 2013 -0800
+++ b/modules/parser.tp	Wed Nov 27 23:36:24 2013 -0800
@@ -1,4 +1,7 @@
 #{
+	_applyMatch <- :fun tomatch {
+		fun: tomatch
+	}
 	expandClass <- :chars {
 		if: (chars length) > 0 {
 			pos <- 0
@@ -90,20 +93,73 @@
 			print: "uh oh"
 		}
 	}
-	alpha <- charClass: "a-zA-Z"
+
+	zeroPlus <- macro: :matchexpr {
+		funexpr <- false
+		valid <- false
+		matchcall <- if: (matchexpr nodeType) = "lambda" {
+			valid <- true
+			quote: (_applyMatch: matchexpr tomatch)
+		} else: {
+			if: (matchexpr nodeType) = "symbol" {
+				valid <- true
+				quote: (matchexpr: tomatch)
+			}
+		}
+		if: valid {
+			quote: :tomatch {
+				cur <- 0
+				n <- tomatch byte_length
+				orig <- tomatch
+				match <- true
+				while: { match && cur < n } do: {
+					res <- matchcall
+					match <- res matched?
+					if: match {
+						//TODO: Use some kind of lightweight substring wrapper here
+						tomatch <- tomatch from: (res matchlen)
+						cur <- cur + (res matchlen)
+					}
+				}
+				if: cur > 0 {
+					#{
+						matched? <- { true }
+						matchlen <- { cur }
+					}
+				} else: {
+					#{
+						matched? <- { false }
+					}
+				}
+			}
+		} else: {
+			print: "#error Invalid zeroPlus macro call\n"
+		}
+	}
+
+
+	_alpha <- charClass: "a-zA-Z"
+	alpha <- zeroPlus: _alpha
+	alphaNum <- zeroPlus: (charClass: "a-zA-Z0-9")
 
 	main <- {
-		cmatch <- alpha: "c0123"
+		cmatch <- alpha: "czx0123"
 		zeromatch <- alpha: "01234"
 		if: (cmatch matched?) {
-			print: "c0123 matched with length " . (cmatch matchlen) . "\n"
+			print: "czx0123 matched with length " . (cmatch matchlen) . "\n"
 		} else: {
-			print: "c0123 didn't match\n"
+			print: "czx0123 didn't match\n"
 		}
 		if: (zeromatch matched?) {
 			print: "0123 matched with length " . (zeromatch matchlen) . "\n"
 		} else: {
 			print: "0123 didn't match\n"
 		}
+		zeromatchanum <- alphaNum: "01234"
+		if: (zeromatchanum matched?) {
+			print: "01234 matched with length " . (zeromatchanum matchlen) . "\n"
+		} else: {
+			print: "01234 didn't match\n"
+		}
 	}
 }