changeset 98:094227f2f64e

Merge
author Mike Pavone <pavone@retrodev.com>
date Thu, 26 Jul 2012 23:41:54 -0700
parents 59a94f3ad56f (diff) 6735db9b44ba (current diff)
children b58b19c455ec
files
diffstat 7 files changed, 161 insertions(+), 42 deletions(-) [+]
line wrap: on
line diff
--- a/cbackend.js	Tue Jul 24 01:01:00 2012 -0700
+++ b/cbackend.js	Thu Jul 26 23:41:54 2012 -0700
@@ -13,7 +13,7 @@
 }
 
 op.prototype.toC = function(isReceiver) {
-	var optoMeth = {'+': 'ADD_', '-': 'SUB_', '*': 'MUL_', '/': 'DIV_', '%': 'MOD_', '=': 'EQ_', '!=': 'NEQ_', '<': 'LT_', '>': 'GT_', '>=': 'GEQ_', '<=': 'LEQ_', '.': 'CAT_'};
+	var optoMeth = {'+': 'ADD_', '-': 'SUB_', '*': 'MUL_', '/': 'DIV_', '%': 'MOD_', '=': 'EQ_', '!=': 'NEQ_', '<': 'LT_', '>': 'GT_', '>=': 'GEQ_', '<=': 'LEQ_', '.': 'CAT_', '&&':'if', '||':'ifnot'};
 	var method = optoMeth[this.op];
 	return 'mcall(' + getMethodId(method) + '/* ' + method + ' */, 2, (object *)' + this.left.toC() + ', ' + this.right.toC() + ')\n';
 };
@@ -237,7 +237,11 @@
 	}
 	var callpart;
 	if (method) {
-		callpart = 'mcall(' + getMethodId(name) + '/* ' + name + ' */';
+		if (funinfo && funinfo.type == 'self' && funinfo.def.name) {
+			callpart =  funinfo.def.name + '(' + (funinfo.def.symbols.parent.needsenv ? (new symbol('self', this.symbols)).toC() + '->env' : 'NULL' );
+		} else {
+			callpart = 'mcall(' + getMethodId(name) + '/* ' + name + ' */';
+		}
 	} else {
 		callpart = 'ccall(' + (new symbol(name, this.symbols)).toC();
 	}
@@ -767,15 +771,7 @@
 	toplevel.names['os'] = os;
 }
 
-modulefile.prototype.populateSymbols = function (toplevel) {
-	if (!this.ast) {
-		this.ast = parseFile(this.path + '/' + this.file);
-		this.ast.populateSymbols(toplevel);
-	}
-};
-
 modulefile.prototype.toC = function(){
-	this.populateSymbols(toplevel);
 	return this.ast.toCModuleInstance();
 };
 
@@ -842,15 +838,13 @@
 	return this.toC();
 }
 
-var lambdanum = 0;
-
 lambda.prototype.toC = function() {
 	var args = this.args ? this.args.slice(0, this.args.length) : [];
 	var exprs = this.expressions;
-	var mynum = lambdanum++;
-	debugprint('//lambda', mynum);
+	debugprint('//', this.name);
 	if (Object.keys(this.symbols.closedover).length) {
-		this.symbols.envtype = 'lambda_' + mynum + '_env';
+		this.symbols.envtype = this.name + '_env';
+		forwarddec += 'typedef struct ' + this.symbols.envtype + '  ' + this.symbols.envtype + ';\n'
 	}
 	if (this.selftype) {
 		this.symbols.defineVar('self', this.selftype);
@@ -879,7 +873,7 @@
 	}
 	
 	if (Object.keys(this.symbols.closedover).length) {
-		forwarddec += 'typedef struct lambda_' + mynum + '_env {\n';
+		forwarddec += 'struct ' + this.name + '_env {\n';
 		if (this.symbols.needsParentEnv) {
 			forwarddec += '\tstruct ' + this.symbols.parentEnvType() + ' * parent;\n';
 		}
@@ -890,18 +884,19 @@
 				forwarddec += '\tobject * ' + escapeCName(varname) + ';\n';
 			}
 		}
-		forwarddec += '} lambda_' + mynum + '_env;\n'
+		forwarddec += '};\n'
 		
-		var myenvinit = '\tlambda_' + mynum + '_env * myenv = GC_MALLOC(sizeof(lambda_' + mynum + '_env));\n';
+		var myenvinit = '\t' + this.name + '_env * myenv = GC_MALLOC(sizeof(' + this.name + '_env));\n';
 		if (this.symbols.needsParentEnv) {
 			myenvinit += '\tmyenv->parent = env;\n';
 		}
-		this.symbols.envtype = 'lambda_' + mynum + '_env';
+		this.symbols.envtype = this.name + '_env';
 	} else {
 		var myenvinit = '';
 	}
+	forwarddec += 'object *' + this.name + ' (' + this.symbols.parentEnvType() + ' * env, uint32_t num_args, ...);\n';
 	
-	toplevelcode +=  'object * lambda_' + mynum + ' (' + this.symbols.parentEnvType() + ' * env, uint32_t num_args, ...) {\n\tva_list args;\n' + myenvinit + '\tva_start(args, num_args);\n';
+	toplevelcode +=  'object * ' + this.name + ' ( ' + this.symbols.parentEnvType() + ' * env, uint32_t num_args, ...) {\n\tva_list args;\n' + myenvinit + '\tva_start(args, num_args);\n';
 	if (this.selftype) {
 		var selfvar = (new symbol('self', this.symbols)).toC();
 		if (selfvar == 'self') {
@@ -912,7 +907,6 @@
 		
 	}
 	toplevelcode += args.join('') + '\tva_end(args);\n' + exprs.join(';\n\t') + '\n}\n';
-	this.name = 'lambda_' + mynum;
 	
 	if (this.selftype) {
 		return this.name;
@@ -923,11 +917,11 @@
 			} else {
 				var envvar = 'myenv';
 			}
-			debugprint('//lambda_' + mynum, 'has envvar:', envvar, 'num vars closed over:', Object.keys(this.symbols.closedover).length);
+			debugprint('//' + this.name, 'has envvar:', envvar, 'num vars closed over:', Object.keys(this.symbols.closedover).length);
 			return 'make_lambda(' + envvar + ', (closure_func)' + this.name + ')';
 		} else {	
-			toplevelcode += 'lambda lambda_obj_' + mynum + ' = {{&lambda_meta, NULL}, NULL, lambda_' + mynum + '};\n';
-			return '((object *)&lambda_obj_' + mynum + ')';
+			toplevelcode += 'lambda ' + this.name + '_obj = {{&lambda_meta, NULL}, NULL, lambda_' + mynum + '};\n';
+			return '((object *)&' + this.name + '_obj)';
 		}
 	}
 };
--- a/compiler.js	Tue Jul 24 01:01:00 2012 -0700
+++ b/compiler.js	Thu Jul 26 23:41:54 2012 -0700
@@ -11,6 +11,13 @@
 	this.file = file;
 }
 
+modulefile.prototype.populateSymbols = function (toplevel) {
+	if (!this.ast) {
+		this.ast = parseFile(this.path + '/' + this.file);
+		this.ast.populateSymbols(toplevel);
+	}
+};
+
 var toplevel = new topsymbols([]);
 function topsymbols(moduledirs)
 {
@@ -289,6 +296,12 @@
 
 op.prototype.populateSymbols = function(symbols, isReceiver) {
 	this.left.populateSymbols(symbols);
+	if (this.op == '&&' || this.op == '||') {
+		//&& and || are syntactic sugar for if and ifnot with
+		//the second argument transformed into a lambda to
+		//achieve short-circuit evalutation
+		this.right = new lambda([], [this.right]);
+	}
 	this.right.populateSymbols(symbols);
 };
 
@@ -322,6 +335,7 @@
 }
 
 funcall.prototype.populateSymbols = function(symbols) {
+	var isll = false;
 	if (this.name == 'foreign:') {
 		if ((this.args[0] instanceof lambda) || (this.args[0] instanceof object) || (this.args[0] instanceof symbol)) {
 			return;
@@ -344,6 +358,7 @@
 			if (this.args[1] instanceof lambda) {
 				if (this.args[2] instanceof lambda) {
 					symbols.defineMsg(this.args[0].name, this.args[2]);
+					isll = true;
 				} else {
 					throw new Error("Third argument to llMessage:withVars:andCode: must be a lambda");
 				}
@@ -361,10 +376,10 @@
 		symbols.find('self');
 	}
 	for (var i in this.args) {
-		this.args[i].populateSymbols(symbols);
+		this.args[i].populateSymbols(symbols, undefined, isll);
 	}
 	if (this.receiver) {
-		this.receiver.populateSymbols(symbols);
+		this.receiver.populateSymbols(symbols, undefined, isll);
 	}
 }
 
@@ -379,8 +394,11 @@
 	}
 	this.symbols = symbols;
 }
-
-lambda.prototype.populateSymbols = function(symbols, isobject) {
+var lambdanum = 0;
+lambda.prototype.populateSymbols = function(symbols, isobject, isll) {
+	if (!isll) {
+		this.name = 'lambda_' + lambdanum++;
+	}
 	var args = this.args ? this.args.slice(0, this.args.length) : [];
 	var exprs = this.expressions;
 	var symbols = new lsymbols(symbols);
--- a/jsbackend.js	Tue Jul 24 01:01:00 2012 -0700
+++ b/jsbackend.js	Thu Jul 26 23:41:54 2012 -0700
@@ -45,10 +45,8 @@
 }
 
 op.prototype.toJS = function(isReceiver) {
-	var ret = '(' + this.left.toJS() +' '+ (this.op == '=' ? '==' : this.op) +' '+ this.right.toJS() + ')';
-	if (isReceiver) {
-		ret = 'toobj' + ret;
-	}
+	var opmap = {'=': '==', '.': '+'};
+	var ret = '(' + this.left.toJS() +' '+ (this.op in opmap ? opmap[this.op] : this.op) +' '+ this.right.toJS() + ')';
 	return ret;
 };
 
@@ -80,8 +78,7 @@
 			pre += '.parent';
 		}
 	} else if (info.type == 'toplevel') {
-		pre = 'modules.';
-		modules[name] = false;
+		return toplevel.moduleVar(name);
 	}
 	return pre + escapeJSName(name);
 }
@@ -122,22 +119,21 @@
 		args.splice(0, 0, this.receiver);
 	}
 	var funinfo = this.symbols.find(name);
-	if (!funinfo || funinfo.def instanceof setter) {
+	if (!funinfo || funinfo.def instanceof setter || funinfo.type == 'toplevel') {
 		var receiver = args[0];
 		args.splice(0, 1);
 		for (var i in args) {
 			args[i] = args[i].toJS();
 		}
-		var rJS = receiver.toJS(true);
+		var rJS = (funinfo ? '' : 'toobj(') + receiver.toJS(true) + (funinfo ? '' : ')') ;
 		if ((name[name.length-1] == '!' && args.length == 1) || (funinfo && funinfo.def instanceof setter)) {
 			return  '(' + rJS + '.' + escapeJSName(name.substr(0, name.length-1))  + ' = ' + args[0] + ', ' + rJS + ')';
 		} else {
 			var callee = rJS + '.' + escapeJSName(name);
-			var callCode = callee + '(' + args.join(', ') + ')';
 			if (args.length == 0) {
-				return '(' + callee + ' instanceof Function ? ' + callCode + ' : ' + callee + ')';
+				return callee;
 			} else {
-				return callCode;
+				return callee + '(' + args.join(', ') + ')';
 			}
 		}
 	}
@@ -214,7 +210,7 @@
 
 object.prototype.toJSModule = function() {
 	this.populateSymbols(toplevel);
-	return '(function () {\n\tvar module = ' + indent(this.toJS()) + ';\n\treturn module;\n})'
+	return '(function () {\n\tvar module = ' + indent(this.toJS()) + ';\n\treturn module;\n})();'
 }
 
 lambda.prototype.toJS = function() {
@@ -239,9 +235,69 @@
 	}
 	return 'function (' + args.join(', ') + ') {\n\t' + (this.symbols.needsSelfVar ? 'var self = this;\n\t' : '') + exprs.join(';\n\t') + '\n}'
 };
+lambda.prototype.nonSelfArgs = function() {
+	var args = this.args ? this.args.slice(0, this.args.length) : [];
+	if (args.length && args[0].cleanName() == 'self') {
+		args.splice(0, 1);
+	}
+	return args;
+};
 lambda.prototype.toJSModule = function() {
 	this.populateSymbols(toplevel);
-	return this.toJS();
+	return this.toJS() + '();';
+}
+
+modulefile.prototype.toJSModule = function(){
+	return this.ast.toJSModule();
+};
+
+function processUsedToplevelJS(toplevel)
+{	
+	var alwaysused = ['true', 'false'];
+	var ret = '';
+	var modulenum = 0;
+	var visited = {};
+	for (var i in alwaysused) {
+		toplevel.used[alwaysused[i]] = true;
+	}
+	var newused = Object.keys(toplevel.used);
+	var allused = newused;
+	while (newused.length) {
+		for (var i in newused) {
+			toplevel.names[newused[i]].populateSymbols(toplevel);
+			visited[newused[i]] = true;
+		}
+		newused = [];
+		for (var symbol in toplevel.used) {
+			if (!(symbol in visited)) {
+				newused.push(symbol);
+				allused.push(symbol);
+			}
+		}
+	}
+		
+	for (var i = allused.length-1; i >= 0; i--) {
+		var symbol = allused[i];
+		ret += 'var ' + toplevel.moduleVar(symbol) + ' = ' + toplevel.names[symbol].toJSModule() + '\n';
+	}
+	return ret;
+}
+
+function makeJSProg(mainmodule)
+{
+	return processUsedToplevelJS(toplevel) + 'main_module = ' + mainmodule.toJSModule() + '\n' +
+	'Number.prototype.__defineGetter__("string", function() { return "" + this; });\n' +
+	'String.prototype.__defineGetter__("string", function() { return this; });\n' +
+	'String.prototype.__defineGetter__("print", function() { write(this); });\n' +
+	'Array.prototype.foreach = function(action) { var ret = module_false; for (var i = 0; i < this.length; i++) { ret = action(i, this[i]) }; return ret; };\n' +
+	'Function.prototype.whileCN_do = function(action) { var ret = module_false; while(toobj(this()) == module_true) { ret = action(); } return ret; };\n' +
+	'function toobj(val) {\n' + 
+	'	return (typeof val == "boolean") ? (val ? module_true : module_false) : val;\n' + 
+	'}\n' + 
+	'var m = main_module.main;\n' + 
+	'if (m instanceof Function) {\n' + 
+	'	m(arguments);\n' +
+	'}\n';
 }
 
 assignment.prototype.toJS = function() {
@@ -269,10 +325,27 @@
 	}
 	return prefix + this.symbol.toJS() + ' = ' + val;
 };
+function removeInitialFunction(str)
+{
+	var f = 'function';
+	str = str.trim();
+	if (str.substr(0, f.length) == f) {
+		return str.substr(f.length);
+	}
+	return str;
+}
 assignment.prototype.toJSObject = function() {
 	var val = this.expression.toJS();
 	if (val === null) {
 		return null;
 	}
+	if (this.expression instanceof lambda) {
+		var args =  this.expression.nonSelfArgs();
+		if (args.length == 0) {
+			return 'get ' + escapeJSName(this.symbol.name) + removeInitialFunction(val);
+		} else if(args.length == 1 && this.symbol.name[this.symbol.name.length-1] == '!') {
+			return 'set ' + escapeJSName(this.symbol.name.substr(0, this.symbol.name.length-1)) + removeInitialFunction(val);
+		}
+	}
 	return escapeJSName(this.symbol.name) + ': ' + val;
 };
--- a/modules/false.tp	Tue Jul 24 01:01:00 2012 -0700
+++ b/modules/false.tp	Thu Jul 26 23:41:54 2012 -0700
@@ -2,6 +2,9 @@
 	if <- :self trueblock {
 		self
 	}
+	ifnot <- :self falseblock {
+		falseblock:
+	}
 	if:else <- :self trueblock :elseblock {
 		elseblock:
 	}
--- a/modules/true.tp	Tue Jul 24 01:01:00 2012 -0700
+++ b/modules/true.tp	Thu Jul 26 23:41:54 2012 -0700
@@ -2,6 +2,9 @@
 	if <- :self trueblock {
 		trueblock:
 	}
+	ifnot <- :self falseblock {
+		self
+	}
 	if:else <- :self trueblock :elseblock {
 		trueblock:
 	}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/samples/logical.tp	Thu Jul 26 23:41:54 2012 -0700
@@ -0,0 +1,28 @@
+#{
+
+	foo <- {
+		print: "foo\n"
+		true
+	}
+	
+	bar <- {
+		print: "bar\n"
+		false
+	}
+	
+	baz <- {
+		print: "baz\n"
+		true
+	}
+	
+	qux <- {
+		print: "shouldn't be printed\n"
+		true
+	}
+	
+	
+	main <- {
+		foo && bar || (baz || qux)
+	}
+
+}
--- a/tpc.js	Tue Jul 24 01:01:00 2012 -0700
+++ b/tpc.js	Thu Jul 26 23:41:54 2012 -0700
@@ -108,7 +108,7 @@
 		var c = parsed.toCModule();
 		break;
 	case 'JS':
-		var c = parsed.toJSModule();
+		var c = makeJSProg(parsed);
 		break;
 	default:
 		print('Backend', backend, ' not recognized');