view compiler.js @ 19:132c7756860e

Use populateSymbols to generate symbol tables during compilation rather than populating them as we go. This change allows us to refer to symbols defined later in the input stream and also gives the symbol table logic a single home that can be used both by the compiler and editor.
author Mike Pavone <pavone@retrodev.com>
date Sun, 25 Mar 2012 16:11:19 -0700
parents 59e83296e331
children bf03c9f0dd55
line wrap: on
line source

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

function osymbols(parent)
{
	this.parent = parent;
	this.names = {};
	this.lastname = null;
}
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.lastname = name;
	this.names[name] = def;
}
osymbols.prototype.parentObject = function() {
	if (!this.parent) {
		return 'null';
	}
	return 'this';
}

function lsymbols(parent)
{
	this.parent = parent;
	this.names = {};
	this.lastname = null;
	this.needsSelfVar = false;
}
lsymbols.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: 'local',
			def: this.names[name]
		};
	} else if(this.parent) {
		var ret = this.parent.find(name);
		if (ret && ret.type == 'local') {
			ret.type = 'upvar';
		}
		return ret;
	}
	return null;
};
lsymbols.prototype.defineVar = function(name, def) {
	this.lastname = name;
	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;
	}
};

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

function setP(o, p, val)
{
	o[p] = val;
	return o;
}

function getP(o, p)
{
	return o[p];
}

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

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

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

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

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

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);
};
assignment.prototype.populateSymbolsObject = function(symbols) {
	symbols.defineMsg(this.symbol.name, this.expression);
	this.symbol.populateSymbols(symbols);
	this.expression.populateSymbols(symbols);
};