diff compiler.js @ 126:a2d2d8e09291

Merge
author Mike Pavone <pavone@retrodev.com>
date Mon, 05 Aug 2013 23:37:17 -0700
parents d715fb3c39ab
children d6e79885bd3b 18598163e3ef
line wrap: on
line diff
--- a/compiler.js	Mon Aug 05 23:36:18 2013 -0700
+++ b/compiler.js	Mon Aug 05 23:37:17 2013 -0700
@@ -11,23 +11,57 @@
 	this.file = file;
 }
 
+modulefile.prototype.populateSymbols = function (toplevel) {
+	if (!this.ast) {
+		this.ast = parseFile(this.path + '/' + this.file);
+		this.ast.populateSymbols(toplevel);
+	}
+};
+
+modulefile.prototype.popuplateSymbolsAsync = function(toplevel, whenDone) {
+	if (!this.ast) {
+		var self = this;
+		get(this.path + '/' + this.file, function(data) {
+			self.ast = parser.parse(data.responseText);
+			self.ast.populateSymbols(toplevel);
+			whenDone();
+		});
+	} else {
+		whenDone();
+	}
+};
+
+function getfileshtml(path, data, names)
+{
+	var fakeEl = newEl("div", {
+		innerHTML: data.response
+	});
+	each(qall('a', fakeEl), function(idx, a) {
+		var tpidx = a.textContent.indexOf('.tp');
+		var modname = a.textContent.substr(0, tpidx);
+		if (tpidx > -1) {
+			names[modname] = new modulefile(path, modname + '.tp');
+		}
+	});
+}
+
 var toplevel = new topsymbols([]);
 function topsymbols(moduledirs)
 {
 	this.names = null;
 	this.used = {};
 	this.nextmodulenum = 0;
+	this.onready = null;
 	var self = this;
 	if (typeof window === "object") {
-		get('/src/', function(data) {
-			self.names = {};
-			var fakeEl = newEl("div", {
-				innerHTML: data.response
-			});
-			each(qall('a', fakeEl), function(idx, a) {
-				var tpidx = a.textContent.indexOf('.tp');
-				if (tpidx > -1) {
-					self.names[a.textContent.substr(0, tpidx)] = true;
+		get('/modules/', function(data) {
+			var names = {}
+			getfileshtml('/modules', data, names);
+			get('/src/', function(data) {
+				getfileshtml('/src', data, names);
+				self.names = names;
+				if (self.onready) {
+					self.onready();
 				}
 			});
 		});
@@ -57,10 +91,10 @@
 		};
 	}
 	return null;
-}
+};
 topsymbols.prototype.getEnvType = function() {
 	return 'void';
-}
+};
 topsymbols.prototype.moduleVar = function(name) {
 	if (!(name in this.names)) {
 		throw new Error('symbol ' + name + ' not found at toplevel');
@@ -72,17 +106,33 @@
 		this.names[name].modulevar = 'module_' + this.nextmodulenum++
 	}
 	return this.names[name].modulevar;
-}
+};
+topsymbols.prototype.onReady = function(fun) {
+	if (this.names) {
+		fun();
+		return;
+	}
+	if (!this.onready) {
+		this.onready = fun;
+	} else {
+		var oldready = this.onready;
+		this.onready = function() {
+			oldready();
+			fun();
+		};
+	}
+};
 
 function osymbols(parent)
 {
 	this.parent = parent;
 	this.names = {};
+	this.llnames = {};
 	this.needsenv = false;
 	this.typename = null;
 	this.needsparent = false;
 }
-osymbols.prototype.find = function(name, nestedcall) {
+osymbols.prototype.find = function(name, nestedcall, allowll) {
 	debugprint('//osymbols.find', name + ', exists?:', name in this.names, ', nested?:', nestedcall);
 	if (name in this.names) {
 		if (this.names[name] instanceof funcall && this.names[name].name == 'foreign:') {
@@ -93,11 +143,18 @@
 		}
 		var ret = {
 			type: 'self',
+			isll: false,
 			def: this.names[name],
 			selftype: this.typename
 		};
+	} else if(allowll && name in this.llnames) {
+		return {
+			type: 'self',
+			isll: true,
+			selftype: this.typename
+		};
 	} else if(this.parent) {
-		var ret = this.parent.find(name, nestedcall);
+		var ret = this.parent.find(name, nestedcall, allowll);
 		if (ret) {
 			if(ret.type == 'self') {
 				ret.type = 'parent';
@@ -119,6 +176,9 @@
 osymbols.prototype.defineMsg = function(name, def) {
 	this.names[name] = def;
 }
+osymbols.prototype.defineLLProperty = function(name) {
+	this.llnames[name] = true;
+}
 osymbols.prototype.parentObject = function() {
 	if (!this.parent) {
 		return 'null';
@@ -160,7 +220,7 @@
 	this.envtype = 'void';
 	this.needsParentEnv = false;
 }
-lsymbols.prototype.find = function(name, nestedcall) {
+lsymbols.prototype.find = function(name, nestedcall, allowll) {
 	debugprint('//lsymbols.find', name + ', exists?:', name in this.names, ', nested?:', nestedcall);
 	if (name in this.names) {
 		if (this.names[name] instanceof funcall && this.names[name].name == 'foreign:') {
@@ -187,7 +247,7 @@
 			}
 		}
 	} else if(this.parent) {
-		var ret = this.parent.find(name, true);
+		var ret = this.parent.find(name, true, allowll);
 		if (ret) {
 			if (ret.type == 'closedover') {
 				ret.type = 'upvar';
@@ -262,22 +322,17 @@
 
 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;
 }
 
 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);
 };
 
@@ -311,12 +366,39 @@
 }
 
 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;
 		} else {
 			throw new Error("Unexpected AST type for foreign:");
 		}
+	} else if (this.name == 'llProperty:withType:') {
+		if (this.args[0] instanceof symbol) {
+			if ((this.args[1] instanceof symbol) || (this.args[1] instanceof funcall)) {
+				symbols.defineLLProperty(this.args[0].name);
+				return;
+			} else {
+				throw new Error("Second argument to llProperty:withType: must be a symbol or funcall");
+			}
+		} else {
+			throw new Error("First argument to llProperty:withType: must be a symbol");
+		}
+	} else if (this.name == 'llMessage:withVars:andCode:') {
+		if (this.args[0] instanceof symbol) {
+			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");
+				}
+			} else {
+				throw new Error("Second argument to llMessage:withVars:andCode: must be a lambda");
+			}
+		} else {
+			throw new Error("First argument to llMessage:withVars:andCode: must be a symbol");
+		}
 	}
 	this.symbols = symbols;
 	var name = this.name[this.name.length-1] == ':' ? this.name.substr(0, this.name.length-1) : this.name;
@@ -325,26 +407,29 @@
 		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);
 	}
 }
 
 funcall.prototype.populateSymbolsObject = function(symbols) {
-	this.populateSymbols(symbols.parent);
+	this.populateSymbols(symbols);
 }
 
 object.prototype.populateSymbols = function(symbols) {
-	symbols = new osymbols(symbols);
+	var symbols = new osymbols(symbols);
 	for (var i in this.messages) {
 		this.messages[i].populateSymbolsObject(symbols);
 	}
 	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);
@@ -394,3 +479,4 @@
 	this.fun = fun;
 }
 getter.prototype.args = [new symbol('self')];
+