diff jsbackend.js @ 126:a2d2d8e09291

Merge
author Mike Pavone <pavone@retrodev.com>
date Mon, 05 Aug 2013 23:37:17 -0700
parents a83989115028
children
line wrap: on
line diff
--- a/jsbackend.js	Mon Aug 05 23:36:18 2013 -0700
+++ b/jsbackend.js	Mon Aug 05 23:37:17 2013 -0700
@@ -3,18 +3,7 @@
 
 function toobj(val)
 {
-	switch(typeof val)
-	{
-	case 'boolean':
-		if(val) {
-			return mainModule.strue;
-		} else {
-			return mainModule.sfalse;
-		}
-	case 'number':
-		return mainModule.snumber(val);
-	}
-	throw new Error("can't make val into object");
+	return (typeof val == "boolean") ? (val ? module_true : module_false) : val;
 }
 
 function importSym(obj, src, key)
@@ -45,9 +34,13 @@
 }
 
 op.prototype.toJS = function(isReceiver) {
-	var ret = '(' + this.left.toJS() +' '+ (this.op == '=' ? '==' : this.op) +' '+ this.right.toJS() + ')';
-	if (isReceiver) {
-		ret = 'toobj' + ret;
+	if (this.op == '&&') {
+		var ret = 'toobj(' + this.left.toJS() + ').sif(' + this.right.toJS() + ')';
+	} else if(this.op == '||') {
+		var ret = 'toobj(' + this.left.toJS() + ').ifnot(' + this.right.toJS() + ')';
+	} else {
+		var opmap = {'=': '==', '.': '+'};
+		var ret = '(' + this.left.toJS() +' '+ (this.op in opmap ? opmap[this.op] : this.op) +' '+ this.right.toJS() + ')';
 	}
 	return ret;
 };
@@ -80,8 +73,7 @@
 			pre += '.parent';
 		}
 	} else if (info.type == 'toplevel') {
-		pre = 'modules.';
-		modules[name] = false;
+		return toplevel.moduleVar(name);
 	}
 	return pre + escapeJSName(name);
 }
@@ -122,22 +114,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(', ') + ')';
 			}
 		}
 	}
@@ -145,7 +136,7 @@
 	switch(funinfo.type)
 	{
 	case 'self':
-		if (args.length < funinfo.def.args.length || funinfo.def.args[0].name != 'self') {
+		if (args.length < funinfo.def.args.length || funinfo.def.args.length == 0 || funinfo.def.args[0].name != 'self') {
 			var receiver = new symbol('self', this.symbols);
 		} else {
 			var receiver = args[0];
@@ -160,7 +151,8 @@
 		ret = receiver.toJS(true) + '.';
 		break;
 	case 'parent':
-		ret = 'this';
+		var receiver = new symbol('self', this.symbols);
+		ret = receiver.toJS(true);
 		for (var i = 0; i < funinfo.depth; ++i) {
 			ret += '.parent';
 		}
@@ -214,7 +206,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,40 +231,162 @@
 	}
 	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 = 0; i < alwaysused.length; i++) {
+		toplevel.used[alwaysused[i]] = true;
+	}
+	var newused = Object.keys(toplevel.used);
+	var allused = newused;
+	while (newused.length) {
+		for (var i = 0; i < newused.length; i++) {
+			console.log(i, newused[i]);
+			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 asyncProcessTopLevelJS(toplevel, whenDone)
+{
+	var alwaysused = ['true', 'false'];
+	var ret = '';
+	var modulenum = 0;
+	var visited = {};
+	for (var i = 0; i < alwaysused.length; i++) {
+		toplevel.used[alwaysused[i]] = true;
+	}
+	var newused = Object.keys(toplevel.used);
+	var allused = newused;
+	var i = -1;
+	var handler = function() {
+		i++;
+		while(newused.length)
+		{
+			if (i < newused.length) {
+				visited[newused[i]] = true;
+				toplevel.names[newused[i]].popuplateSymbolsAsync(toplevel, handler);
+				return;
+			} else {
+				newused = [];
+				for (var symbol in toplevel.used) {
+					if (!(symbol in visited)) {
+						newused.push(symbol);
+						allused.push(symbol);
+					}
+				}
+				i = 0;
+			}
+		}
+		whenDone();
+	};
+	handler();
+}
+
+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' +
+	'Object.defineProperty(Array.prototype, "foreach", {value: 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' +
+	'module_true.valueOf = function() { return true; }\n' +
+	'module_false.valueOf = function() { return false; }\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() {
 	var existing = this.symbols.find(this.symbol.name);
 	var prefix = '';
-	if (!existing) {
+	/*if (!existing) {
 		prefix =  'var ';
 	} else {
 		switch (existing.type)
 		{
 		case 'self':
-			prefix = 'this.';
+			var self = new symbol('self', this.symbols);
+			prefix = self.toJS() + '.';
 			break;
 		case 'parent':
-			prefix = 'this.';
+			var self = new symbol('self', this.symbols);
+			prefix = self.toJS() + '.';
 			for (var i = 0; i < existing.depth; ++i) {
 				prefix += 'parent.';
 			}
 			break;
 		}
-	}
+	}*/
 	var val = this.expression.toJS();
 	if (val === null) {
 		return null;
 	}
+	if ((existing.type == 'local' || existing.type == 'closedover') && !existing.isdeclared) {
+		prefix = 'var ';
+		this.symbols.declareVar(this.symbol.name);
+	}
 	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;
 };