view compiler.js @ 34:a10f1b049193

Working closures, but need to rethink method call strategy
author Mike Pavone <pavone@retrodev.com>
date Mon, 09 Jul 2012 08:57:50 -0700
parents 668f533e5284
children bf5e88f6419d
line wrap: on
line source

function indent(str)
{
	return str.split('\n').join('\n\t');
}

var toplevel = new topsymbols();
function topsymbols()
{
	this.names = null;
	var self = this;
	get('/src/', function(data) {
		console.log(data);
		self.names = {};
		var fakeEl = newEl("div", {
			innerHTML: data.response
		});
		console.log(fakeEl);
		each(qall('a', fakeEl), function(idx, a) {
			var tpidx = a.textContent.indexOf('.tp');
			if (tpidx > -1) {
				self.names[a.textContent.substr(0, tpidx)] = true;
			}
		});
	});
}
topsymbols.prototype.find = function(name) {
	console.log(this.names);
	if (!this.names) {
		throw new Error('data not ready');
	}
	console.log('toplevel', name);
	if (name in this.names) {
		return {
			type: 'toplevel',
			def: null
		};
	}
	return null;
}
topsymbols.prototype.getEnvType = function() {
	return 'void';
}

function osymbols(parent)
{
	this.parent = parent;
	this.names = {};
}
osymbols.prototype.find = function(name) {
	if (name in this.names) {
		if (this.names[name] instanceof funcall && this.names[name].name == 'foreign:') {
			return {
				type: 'foreign',
				def: this.names[name]
			};
		}
		return {
			type: 'self',
			def: this.names[name],
		};
	} else if(this.parent) {
		var ret = this.parent.find(name);
		if (ret) {
			if(ret.type == 'self') {
				ret.type = 'parent';
				ret.depth = 1;
			} else if(ret.type == 'parent') {
				ret.depth++;
			}
		}
		return ret;
	}
	return null;
};
osymbols.prototype.defineMsg = function(name, def) {
	this.names[name] = def;
}
osymbols.prototype.parentObject = function() {
	if (!this.parent) {
		return 'null';
	}
	return 'this';
}
osymbols.prototype.allSymbols = function(curlist, cursyms) {
	if (curlist === undefined) {
		curlist = [];
		cursyms = {};
	}
	var keys = Object.keys(this.names).sort();
	for (var i in keys) {
		if (!(keys[i] in cursyms)) {
			curlist.push(keys[i]);
			cursyms[keys[i]] = true;
		}
	}
	if (this.parent) {
		return this.parent.allSymbols(curlist, cursyms);
	}
	return curlist;
}
osymbols.prototype.getEnvType = function() {
	console.log('osymbol parent', this.parent);
	return this.parent.getEnvType();
}

function lsymbols(parent)
{
	this.parent = parent;
	this.names = {};
	this.closedover = {};
	this.needsSelfVar = false;
	this.passthruenv = false;
	this.envtype = 'void';
}
lsymbols.prototype.find = function(name, nestedcall) {
	console.log('find', name, nestedcall);
	if (name in this.names) {
		if (this.names[name] instanceof funcall && this.names[name].name == 'foreign:') {
			return {
				type: 'foreign',
				def: this.names[name]
			};
		}
		if (nestedcall) {
			console.log('closedover', name);
			this.closedover[name] = true;
		} 
		if (name in this.closedover) {
			return {
				type: 'closedover',
				def: this.names[name]
			};
		}
		return {
			type: 'local',
			def: this.names[name]
		};
	} else if(this.parent) {
		var ret = this.parent.find(name, true);
		if (ret) {
			if (ret.type == 'closedover') {
				ret.type = 'upvar';
				ret.depth = 1;
			} else if (ret.type == 'upvar') {
				if (Object(this.closedover).keys.length) {
					ret.depth++;
				} else {
					this.passthruenv = true;
				}
			}
		}
		return ret;
	}
	return null;
};
lsymbols.prototype.defineVar = function(name, def) {
	this.names[name] = def;
};
lsymbols.prototype.selfVar = function() {
	if (this.parent && this.parent instanceof lsymbols) {
		this.parent.needsSelf();
		return 'self';
	} else {
		return 'this';
	}
};
lsymbols.prototype.needsSelf = function() {
	if (this.parent && this.parent instanceof lsymbols) {
		this.parent.needsSelf();
	} else {
		this.needsSelfVar = true;
	}
};
lsymbols.prototype.allSymbols = osymbols.prototype.allSymbols;
lsymbols.prototype.parentEnvType = function() {
	if (!this.parent) {
		return 'void';
	}
	return this.parent.getEnvType();
};
lsymbols.prototype.getEnvType = function() {
	if (this.passthruenv) {
		console.log('lsymbol parent', this.parent);
		return this.parent.getEnvType();
	} else {
		return this.envtype;
	}
}

var mainModule;

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");
}

op.prototype.populateSymbols = function(symbols, isReceiver) {
	this.left.populateSymbols(symbols);
	this.right.populateSymbols(symbols);
};

symbol.prototype.populateSymbols = function(symbols) {
	this.symbols = symbols;
	symbols.find(this.cleanName());
}

intlit.prototype.populateSymbols = function(symbols) {
}

floatlit.prototype.populateSymbols = function(symbols) {
}

strlit.prototype.populateSymbols = function(symbols) {
}

listlit.prototype.populateSymbols = function(symbols) {
	each(this.val, function(i,el) {
		el.populateSymbols(symbols);
	});
}

funcall.prototype.populateSymbols = function(symbols) {
	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:");
		}
	}
	this.symbols = symbols;
	for (var i in this.args) {
		this.args[i].populateSymbols(symbols);
	}
	if (this.receiver) {
		this.receiver.populateSymbols(symbols);
	}
}

funcall.prototype.populateSymbolsObject = function(symbols) {
	this.populateSymbols(symbols.parent);
}

object.prototype.populateSymbols = function(symbols) {
	symbols = new osymbols(symbols);
	for (var i in this.messages) {
		this.messages[i].populateSymbolsObject(symbols);
	}
	this.symbols = symbols;
}

lambda.prototype.populateSymbols = function(symbols) {
	var args = this.args ? this.args.slice(0, this.args.length) : [];
	if (args.length && args[0].cleanName() == 'self') {
		args.splice(0, 1);
	}
	var exprs = this.expressions;
	symbols = new lsymbols(symbols);
	for (var i in args) {
		symbols.defineVar(args[i].cleanName(), null);
		args[i].populateSymbols(symbols);
	}
	for (var i in exprs) {
		exprs[i].populateSymbols(symbols);
	}
	this.symbols = symbols;
};

assignment.prototype.populateSymbols = function(symbols) {
	var existing = symbols.find(this.symbol.name);
	if (!existing) {
		symbols.defineVar(this.symbol.name, this.expression);
	}
	this.symbol.populateSymbols(symbols);
	this.expression.populateSymbols(symbols);
	this.symbols = symbols;
};
assignment.prototype.populateSymbolsObject = function(symbols) {
	if (this.expression instanceof lambda || (this.expression instanceof funcall & this.expression.name == 'foreign:')) {
		symbols.defineMsg(this.symbol.name, this.expression);
	} else {
		symbols.defineMsg(this.symbol.name, new getter(null));
		symbols.defineMsg(this.symbol.name + '!', new setter(null));
	}
	this.symbol.populateSymbols(symbols);
	this.expression.populateSymbols(symbols);
	this.symbols = symbols;
};

function setter(fun)
{
	this.fun = fun;
}
setter.prototype.args = [new symbol('self'), new symbol('newval')];
function getter(fun)
{
	this.fun = fun;
}
getter.prototype.args = [new symbol('self')];