changeset 8:04ae32e91598

Move compiler and test page related code out of parser.js
author Mike Pavone <pavone@retrodev.com>
date Wed, 21 Mar 2012 20:33:39 -0700
parents 8af72f11714e
children 37d7f60a8ea1
files compiler.js jsbackend.js parser.js testparse.html testparse.js
diffstat 5 files changed, 309 insertions(+), 296 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/compiler.js	Wed Mar 21 20:33:39 2012 -0700
@@ -0,0 +1,96 @@
+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;
+	}
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jsbackend.js	Wed Mar 21 20:33:39 2012 -0700
@@ -0,0 +1,175 @@
+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.toJS = function(symbols, isReceiver) {
+	var ret = '(' + this.left.toJS(symbols) +' '+ (this.op == '=' ? '==' : this.op) +' '+ this.right.toJS(symbols) + ')';
+	if (isReceiver) {
+		ret = 'toobj' + ret;
+	}
+	return ret;
+};
+
+symbol.prototype.toJS = function(symbols) {
+	var name = this.cleanName();
+	if (name == 'self') {
+		return 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};
+	if (name in reserved) {
+		name = 's' + name;
+	}
+	return name;
+}
+
+intlit.prototype.toJS = function(symbols) {
+	return this.val.toString();
+}
+
+floatlit.prototype.toJS = function(symbols) {
+	return this.val.toString();
+}
+
+strlit.prototype.toJS = function(symbols) {
+	console.log('string:', this.val);
+	return '"' + this.val.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n').replace('\r', '\\r') + '"';
+}
+
+funcall.prototype.toJS = function(symbols) {
+	var name = this.name[this.name.length-1] == ':' ? this.name.substr(0, this.name.length-1) : this.name;
+	var args = this.args.slice(0, this.args.length);
+	if (this.receiver) {
+		args.splice(0, 0, this.receiver);
+	}
+	var funinfo = symbols.find(name);
+	if (!funinfo) {
+		var receiver = args[0];
+		args.splice(0, 1);
+		for (var i in args) {
+			args[i] = args[i].toJS(symbols);
+		}
+		return receiver.toJS(symbols, true) + '.' + (new symbol(name)).toJS(symbols) + '(' + 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');
+		} else {
+			var receiver = args[0];
+			args.splice(0, 1);
+		}
+		for (var i in args) {
+			args[i] = args[i].toJS(symbols);
+		}
+		return receiver.toJS(symbols, true) + '.' + (new symbol(name)).toJS(symbols) + '(' + 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);
+		}
+		ret += (new symbol(name)).toJS(symbols) + '(' + args.join(', ') + ')';
+		return ret;
+	case 'local':
+	case 'upvar':
+	case 'foreign':
+		for (var i in args) {
+			args[i] = args[i].toJS(symbols);
+		}
+		return (new symbol(name)).toJS(symbols) + '(' + args.join(', ') + ')';
+	}
+}
+
+object.prototype.toJS = function(symbols) {
+	var messages = this.messages;
+	symbols = new osymbols(symbols);
+	var compiled = []
+	for (var i in messages) {
+		var js = messages[i].toJSObject(symbols);
+		if (js) {
+			compiled.push(indent(js));
+		}
+	}
+	return '{\n\tparent: ' + 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})'
+}
+
+lambda.prototype.toJS = 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] = args[i].toJS(symbols);
+	}
+	var compiled = []
+	for (var i in exprs) {
+		var js = exprs[i].toJS(symbols);
+		if (js) {
+			compiled.push(indent(js));
+		}
+	}
+	exprs = compiled;
+	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}'
+};
+lambda.prototype.toJSModule = lambda.prototype.toJS
+
+assignment.prototype.toJS = function(symbols) {
+	var existing = symbols.find(this.symbol.name);
+	var prefix = '';
+	if (!existing) {
+		symbols.defineVar(this.symbol.name, this.expression);
+		prefix =  'var ';
+	} else {
+		switch (existing.type)
+		{
+		case 'self':
+			prefix = 'this.';
+			break;
+		case 'parent':
+			prefix = 'this.';
+			for (var i = 0; i < existing.depth; ++i) {
+				prefix += 'parent.';
+			}
+			break;
+		}
+	}
+	if (this.expression instanceof funcall && this.expression.name == 'foreign:') {
+		return null;
+	}
+	return prefix + this.symbol.toJS(symbols) + ' = ' + this.expression.toJS(symbols);
+};
+assignment.prototype.toJSObject = function(symbols) {
+	symbols.defineMsg(this.symbol.name, this.expression);
+	if (this.expression instanceof funcall && this.expression.name == 'foreign:') {
+		return null;
+	}
+	return this.symbol.toJS(symbols) + ': ' + this.expression.toJS(symbols);
+};
--- a/parser.js	Wed Mar 21 20:12:12 2012 -0700
+++ b/parser.js	Wed Mar 21 20:33:39 2012 -0700
@@ -1,115 +1,3 @@
-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 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;
-	}
-};
 
 function op(left, op, right)
 {
@@ -117,30 +5,11 @@
 	this.op = op;
 	this.right = right;
 }
-op.prototype.toJS = function(symbols, isReceiver) {
-	var ret = '(' + this.left.toJS(symbols) +' '+ (this.op == '=' ? '==' : this.op) +' '+ this.right.toJS(symbols) + ')';
-	if (isReceiver) {
-		ret = 'toobj' + ret;
-	}
-	return ret;
-};
 
 function symbol(name)
 {
 	this.name = name;
 }
-symbol.prototype.toJS = function(symbols) {
-	var name = this.cleanName();
-	if (name == 'self') {
-		return 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};
-	if (name in reserved) {
-		name = 's' + name;
-	}
-	return name;
-}
 symbol.prototype.cleanName = function() {
 	return this.name[0] == ':' ? this.name.substr(1) : this.name;
 }
@@ -149,26 +18,16 @@
 {
 	this.val = val;
 }
-intlit.prototype.toJS = function(symbols) {
-	return this.val.toString();
-}
 
 function floatlit(val)
 {
 	this.val = val;
 }
-floatlit.prototype.toJS = function(symbols) {
-	return this.val.toString();
-}
 
 function strlit(val)
 {
 	this.val = val;
 }
-strlit.prototype.toJS = function(symbols) {
-	console.log('string:', this.val);
-	return '"' + this.val.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n').replace('\r', '\\r') + '"';
-}
 
 function funcall(name, args)
 {
@@ -176,143 +35,23 @@
 	this.args = args;
 	this.receiver = null;
 }
-funcall.prototype.toJS = function(symbols) {
-	var name = this.name[this.name.length-1] == ':' ? this.name.substr(0, this.name.length-1) : this.name;
-	var args = this.args.slice(0, this.args.length);
-	if (this.receiver) {
-		args.splice(0, 0, this.receiver);
-	}
-	var funinfo = symbols.find(name);
-	if (!funinfo) {
-		var receiver = args[0];
-		args.splice(0, 1);
-		for (var i in args) {
-			args[i] = args[i].toJS(symbols);
-		}
-		return receiver.toJS(symbols, true) + '.' + (new symbol(name)).toJS(symbols) + '(' + 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');
-		} else {
-			var receiver = args[0];
-			args.splice(0, 1);
-		}
-		for (var i in args) {
-			args[i] = args[i].toJS(symbols);
-		}
-		return receiver.toJS(symbols, true) + '.' + (new symbol(name)).toJS(symbols) + '(' + 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);
-		}
-		ret += (new symbol(name)).toJS(symbols) + '(' + args.join(', ') + ')';
-		return ret;
-	case 'local':
-	case 'upvar':
-	case 'foreign':
-		for (var i in args) {
-			args[i] = args[i].toJS(symbols);
-		}
-		return (new symbol(name)).toJS(symbols) + '(' + args.join(', ') + ')';
-	}
-}
 
 function object(messages)
 {
 	this.messages = messages;
 }
-object.prototype.toJS = function(symbols) {
-	var messages = this.messages;
-	symbols = new osymbols(symbols);
-	var compiled = []
-	for (var i in messages) {
-		var js = messages[i].toJSObject(symbols);
-		if (js) {
-			compiled.push(indent(js));
-		}
-	}
-	return '{\n\tparent: ' + 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})'
-}
 
 function lambda(args, expressions)
 {
 	this.args = args;
 	this.expressions = expressions;
 }
-lambda.prototype.toJS = 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] = args[i].toJS(symbols);
-	}
-	var compiled = []
-	for (var i in exprs) {
-		var js = exprs[i].toJS(symbols);
-		if (js) {
-			compiled.push(indent(js));
-		}
-	}
-	exprs = compiled;
-	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}'
-};
-lambda.prototype.toJSModule = lambda.prototype.toJS
 
 function assignment(sym, expr)
 {
 	this.symbol = sym;
 	this.expression = expr;
 }
-assignment.prototype.toJS = function(symbols) {
-	var existing = symbols.find(this.symbol.name);
-	var prefix = '';
-	if (!existing) {
-		symbols.defineVar(this.symbol.name, this.expression);
-		prefix =  'var ';
-	} else {
-		switch (existing.type)
-		{
-		case 'self':
-			prefix = 'this.';
-			break;
-		case 'parent':
-			prefix = 'this.';
-			for (var i = 0; i < existing.depth; ++i) {
-				prefix += 'parent.';
-			}
-			break;
-		}
-	}
-	if (this.expression instanceof funcall && this.expression.name == 'foreign:') {
-		return null;
-	}
-	return prefix + this.symbol.toJS(symbols) + ' = ' + this.expression.toJS(symbols);
-};
-assignment.prototype.toJSObject = function(symbols) {
-	symbols.defineMsg(this.symbol.name, this.expression);
-	if (this.expression instanceof funcall && this.expression.name == 'foreign:') {
-		return null;
-	}
-	return this.symbol.toJS(symbols) + ': ' + this.expression.toJS(symbols);
-};
 
 var grammar = 
 'start = ws module:(object / lambda) ws { return module; };' +
@@ -339,39 +78,4 @@
 'unarymeth = name:symbol { return new funcall(name.name, []); };';
 var parser = PEG.buildParser(grammar);
 
-//var parser = PEG.buildParser('start = expr; expr = int; int = digits:[0-9]+ { return parseInt(digits.join(""), 10); }');
-onReady(function() {
-	q('#parse').onclick = function() {
-		var text = q('textarea').value;
-		try {
-			var parsed = parser.parse(text);
-			q('pre').innerHTML = text + "\n\n" + JSON.stringify(parsed);
-			console.log(parsed);
-		} catch(e) {
-			q('pre').innerHTML = e.message + '\nLine: ' + e.line + '\nCol: ' + e.column;
-		}
-	}
-	q('#tojs').onclick = function() {
-		var text = q('textarea').value;
-		//try {
-			var parsed = parser.parse(text);
-			var js = parsed.toJSModule();
-			q('pre').innerHTML = js;
-			console.log(parsed);
-		/*} catch(e) {
-			q('pre').innerHTML = e.message + '\nLine: ' + e.line + '\nCol: ' + e.column;
-		}*/
-	}
-	q('#run').onclick = function() {
-		var text = q('textarea').value;
-		//try {
-			var parsed = parser.parse(text);
-			var js = parsed.toJSModule();
-			mainModule = eval(js)();
-			q('pre').innerHTML = mainModule.main();
-		/*} catch(e) {
-			q('pre').innerHTML = e.message + '\nLine: ' + e.line + '\nCol: ' + e.column;
-		}*/
-	}
-});
 
--- a/testparse.html	Wed Mar 21 20:12:12 2012 -0700
+++ b/testparse.html	Wed Mar 21 20:33:39 2012 -0700
@@ -5,6 +5,9 @@
 	<script src="peg.js"></script>
 	<script src="mquery.js"></script>
 	<script src="parser.js"></script>
+	<script src="compiler.js"></script>
+	<script src="jsbackend.js"></script>
+	<script src="testparse.js"></script>
 </head>
 <body style="height: 100%">
 	<textarea style="width: 90%; height: 50%; display: block; margin: 0 auto;"></textarea>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/testparse.js	Wed Mar 21 20:33:39 2012 -0700
@@ -0,0 +1,35 @@
+
+onReady(function() {
+	q('#parse').onclick = function() {
+		var text = q('textarea').value;
+		try {
+			var parsed = parser.parse(text);
+			q('pre').innerHTML = text + "\n\n" + JSON.stringify(parsed);
+			console.log(parsed);
+		} catch(e) {
+			q('pre').innerHTML = e.message + '\nLine: ' + e.line + '\nCol: ' + e.column;
+		}
+	}
+	q('#tojs').onclick = function() {
+		var text = q('textarea').value;
+		//try {
+			var parsed = parser.parse(text);
+			var js = parsed.toJSModule();
+			q('pre').innerHTML = js;
+			console.log(parsed);
+		/*} catch(e) {
+			q('pre').innerHTML = e.message + '\nLine: ' + e.line + '\nCol: ' + e.column;
+		}*/
+	}
+	q('#run').onclick = function() {
+		var text = q('textarea').value;
+		//try {
+			var parsed = parser.parse(text);
+			var js = parsed.toJSModule();
+			mainModule = eval(js)();
+			q('pre').innerHTML = mainModule.main();
+		/*} catch(e) {
+			q('pre').innerHTML = e.message + '\nLine: ' + e.line + '\nCol: ' + e.column;
+		}*/
+	}
+});