changeset 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 4dd99fde5f63
children bf03c9f0dd55
files jsbackend.js parser.js
diffstat 2 files changed, 40 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- a/jsbackend.js	Sun Mar 25 15:57:26 2012 -0700
+++ b/jsbackend.js	Sun Mar 25 16:11:19 2012 -0700
@@ -27,18 +27,18 @@
 	return o[p];
 }
 
-op.prototype.toJS = function(symbols, isReceiver) {
-	var ret = '(' + this.left.toJS(symbols) +' '+ (this.op == '=' ? '==' : this.op) +' '+ this.right.toJS(symbols) + ')';
+op.prototype.toJS = function(isReceiver) {
+	var ret = '(' + this.left.toJS() +' '+ (this.op == '=' ? '==' : this.op) +' '+ this.right.toJS() + ')';
 	if (isReceiver) {
 		ret = 'toobj' + ret;
 	}
 	return ret;
 };
 
-symbol.prototype.toJS = function(symbols) {
+symbol.prototype.toJS = function() {
 	var name = this.cleanName();
 	if (name == 'self') {
-		return symbols.selfVar();
+		return this.symbols.selfVar();
 	}
 	name = name.replace("_", "UN_").replace(":", "CN_").replace("!", "EX_").replace('?', 'QS_').replace('@', 'AT_');
 	var reserved = {'true': true, 'false': true, 'this': true, 'if': true, 'else': true, 'NaN': true};
@@ -48,19 +48,19 @@
 	return name;
 }
 
-intlit.prototype.toJS = function(symbols) {
+intlit.prototype.toJS = function() {
 	return this.val.toString();
 }
 
-floatlit.prototype.toJS = function(symbols) {
+floatlit.prototype.toJS = function() {
 	return this.val.toString();
 }
 
-strlit.prototype.toJS = function(symbols) {
+strlit.prototype.toJS = function() {
 	return '"' + this.val.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n').replace('\r', '\\r') + '"';
 }
 
-funcall.prototype.toJS = function(symbols) {
+funcall.prototype.toJS = function() {
 	var name = this.name[this.name.length-1] == ':' ? this.name.substr(0, this.name.length-1) : this.name;
 	if (name == 'foreign') {
 		if ((this.args[0] instanceof lambda) || (this.args[0] instanceof object)) {
@@ -75,79 +75,77 @@
 	if (this.receiver) {
 		args.splice(0, 0, this.receiver);
 	}
-	var funinfo = symbols.find(name);
+	var funinfo = this.symbols.find(name);
 	if (!funinfo) {
 		var receiver = args[0];
 		args.splice(0, 1);
 		for (var i in args) {
-			args[i] = args[i].toJS(symbols);
+			args[i] = args[i].toJS();
 		}
-		return receiver.toJS(symbols, true) + '.' + (new symbol(name)).toJS(symbols) + '(' + args.join(', ') + ')';
+		return receiver.toJS(true) + '.' + (new symbol(name, this.symbols)).toJS() + '(' + args.join(', ') + ')';
 	}
 	switch(funinfo.type)
 	{
 	case 'self':
 		if (args.length < funinfo.def.args.length || funinfo.def.args[0].name != 'self') {
-			var receiver = new symbol('self');
+			var receiver = new symbol('self', this.symbols);
 		} else {
 			var receiver = args[0];
 			args.splice(0, 1);
 		}
 		for (var i in args) {
-			args[i] = args[i].toJS(symbols);
+			args[i] = args[i].toJS();
 		}
-		return receiver.toJS(symbols, true) + '.' + (new symbol(name)).toJS(symbols) + '(' + args.join(', ') + ')';
+		return receiver.toJS(true) + '.' + (new symbol(name, this.symbols)).toJS() + '(' + args.join(', ') + ')';
 	case 'parent':
 		var ret = 'this';
 		for (var i = 0; i < funinfo.depth; ++i) {
 			ret += '.parent';
 		}
 		for (var i in args) {
-			args[i] = args[i].toJS(symbols);
+			args[i] = args[i].toJS();
 		}
-		ret += (new symbol(name)).toJS(symbols) + '(' + args.join(', ') + ')';
+		ret += (new symbol(name, this.symbols)).toJS() + '(' + args.join(', ') + ')';
 		return ret;
 	case 'local':
 	case 'upvar':
 	case 'foreign':
 		for (var i in args) {
-			args[i] = args[i].toJS(symbols);
+			args[i] = args[i].toJS();
 		}
-		return (new symbol(name)).toJS(symbols) + '(' + args.join(', ') + ')';
+		return (new symbol(name, this.symbols)).toJS() + '(' + args.join(', ') + ')';
 	}
 }
 
-object.prototype.toJS = function(symbols) {
+object.prototype.toJS = function() {
 	var messages = this.messages;
-	symbols = new osymbols(symbols);
 	var compiled = []
 	for (var i in messages) {
-		var js = messages[i].toJSObject(symbols);
+		var js = messages[i].toJSObject();
 		if (js) {
 			compiled.push(indent(js));
 		}
 	}
-	return '{\n\tparent: ' + symbols.parentObject() + ',\n\t' + compiled.join(',\n\t') + '\n}';
+	return '{\n\tparent: ' + this.symbols.parentObject() + ',\n\t' + compiled.join(',\n\t') + '\n}';
 }
 
 object.prototype.toJSModule = function() {
-	return '(function () {\n\tvar module = ' + indent(this.toJS(null)) + ';\n\treturn module;\n})'
+	this.populateSymbols(null);
+	return '(function () {\n\tvar module = ' + indent(this.toJS()) + ';\n\treturn module;\n})'
 }
 
-lambda.prototype.toJS = function(symbols) {
+lambda.prototype.toJS = function() {
 	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] = args[i].toJS(symbols);
+		args[i] = args[i].toJS();
 	}
 	var compiled = []
 	for (var i in exprs) {
-		var js = exprs[i].toJS(symbols);
+		var js = exprs[i].toJS();
 		if (js) {
 			compiled.push(indent(js));
 		}
@@ -156,15 +154,17 @@
 	if (exprs.length) {
 		exprs[exprs.length-1] = 'return ' + exprs[exprs.length-1] + ';';
 	}
-	return 'function (' + args.join(', ') + ') {\n\t' + (symbols.needsSelfVar ? 'var self = this;\n\t' : '') + exprs.join(';\n\t') + '\n}'
+	return 'function (' + args.join(', ') + ') {\n\t' + (this.symbols.needsSelfVar ? 'var self = this;\n\t' : '') + exprs.join(';\n\t') + '\n}'
 };
-lambda.prototype.toJSModule = lambda.prototype.toJS
+lambda.prototype.toJSModule = function() {
+	this.populateSymbols(null);
+	return this.toJS();
+}
 
-assignment.prototype.toJS = function(symbols) {
-	var existing = symbols.find(this.symbol.name);
+assignment.prototype.toJS = function() {
+	var existing = this.symbols.find(this.symbol.name);
 	var prefix = '';
 	if (!existing) {
-		symbols.defineVar(this.symbol.name, this.expression);
 		prefix =  'var ';
 	} else {
 		switch (existing.type)
@@ -180,17 +180,16 @@
 			break;
 		}
 	}
-	var val = this.expression.toJS(symbols);
+	var val = this.expression.toJS();
 	if (val === null) {
 		return null;
 	}
-	return prefix + this.symbol.toJS(symbols) + ' = ' + val;
+	return prefix + this.symbol.toJS() + ' = ' + val;
 };
-assignment.prototype.toJSObject = function(symbols) {
-	symbols.defineMsg(this.symbol.name, this.expression);
-	var val = this.expression.toJS(symbols);
+assignment.prototype.toJSObject = function() {
+	var val = this.expression.toJS();
 	if (val === null) {
 		return null;
 	}
-	return this.symbol.toJS(symbols) + ': ' + val;
+	return this.symbol.toJS() + ': ' + val;
 };
--- a/parser.js	Sun Mar 25 15:57:26 2012 -0700
+++ b/parser.js	Sun Mar 25 16:11:19 2012 -0700
@@ -6,9 +6,10 @@
 	this.right = right;
 }
 
-function symbol(name)
+function symbol(name, symbols)
 {
 	this.name = name;
+	this.symbols = symbols;
 }
 symbol.prototype.cleanName = function() {
 	return this.name[0] == ':' ? this.name.substr(1) : this.name;