view parser.js @ 251:2557ce4e671f

Fix a couple of compiler bugs. topenv was getting initialized in multiple places. This resulted in multiple copies of modules getting created which caused problems for macro expansion. Additionally, arguments were not being marked as declared during code generation so assigning to an argument that was not closed over generated invalid C code.
author Michael Pavone <pavone@retrodev.com>
date Fri, 11 Apr 2014 22:29:32 -0700
parents c9cacb06964a
children ddf38b66b2e2
line wrap: on
line source


function op(left, op, right)
{
	this.left = left;
	if (op instanceof Array) {
		op = op[0];
	}
	this.op = op;
	this.right = right;
}
op.prototype.valueOf = function(indent) {
	return this.left.valueOf(indent) + ' ' + this.op.valueOf(indent) + ' ' + this.right.valueOf(indent);
};

function symbol(name, symbols)
{
	this.name = name;
	this.symbols = symbols;
	this.dirty = false;
}
symbol.prototype.cleanName = function() {
	return this.name[0] == ':' ? this.name.substr(1) : this.name;
}
symbol.prototype.valueOf = function() {
	return this.name;
};

function intlit(val, bits, unsigned)
{
	if (!bits) {
		bits = 32;
	}
	if (unsigned === undefined) {
		unsigned = false;
	}
	this.unsigned = unsigned;
	this.bits = bits;
	this.val = val;
}
intlit.prototype.valueOf = function() {
	var val = '' + this.val;
	if (this.bits != 32 || this.unsigned) {
		val += this.unsigned ? 'u' : 'i'
		val += this.bits;
	}
	return val;
};

function floatlit(val)
{
	this.val = val;
}
floatlit.prototype.valueOf = function() {
	return '' + val;
};

function strlit(val)
{
	this.val = val;
}
strlit.prototype.valueOf = function() {
	return '"'+this.val+'"';
};

function listlit(val)
{
	this.val = val;
}
listlit.prototype.valueOf = function(indent) {
	if (indent === undefined) {
		indent = '';
	}
	var nextindent = indent + '\t';
	var val = '['
	for (var i = 0; i < this.val.length; i++) {
		val += '\n' + nextindent + this.val[i].valueOf(nextindent);
	}
	if (this.val.length) {
		val += '\n' + indent;
	}
	val += ']';
	return val;
};

function arraylit(val)
{
	this.val = val;
}
arraylit.prototype.valueOf = function(indent) {
	if (indent === undefined) {
		indent = '';
	}
	var nextindent = indent + '\t';
	var val = '#['
	for (var i = 0; i < this.val.length; i++) {
		val += '\n' + nextindent + this.val[i].valueOf(nextindent);
	}
	if (this.val.length) {
		val += '\n' + indent;
	}
	val += ']';
	return val;
};

function funcall(name, args)
{
	this.name = name;
	this.args = args;
	this.receiver = null;
	this.dirty = false;
}
funcall.prototype.valueOf = function(indent) {
	var parts = this.name.split(':');
	var val = '';
	if (this.receiver) {
		val += this.receiver.valueOf(indent);
	}
	var curarg = 0;
	for (var i = 0; i < parts.length; i++) {
		if (val) {
			val += ' ';
		}
		if (parts[i]) {
			val += parts[i] + ': ';
		}
		if (curarg < this.args.length) {
			val += this.args[curarg++].valueOf(indent);
		}
	}
	while (curarg < this.args.length) {
		val += ' ' + this.args[curarg++].valueOf(indent);
	}
	return val;
};

function object(messages)
{
	this.messages = messages;
	this.name = null;
}
object.prototype.valueOf = function(indent) {
	if (indent === undefined) {
		indent = '';
	}
	var nextindent = indent + '\t';
	var val = '#{';
	for (var i = 0; i < this.messages.length; i++) {
		val += '\n' + nextindent +  this.messages[i].valueOf(nextindent);
	}
	if (val.length > 2) {
		val += '\n' + indent;
	}
	val += '}';
	return val;
};

function lambda(args, expressions)
{
	this.args = args ? args : [];
	this.expressions = expressions;
}
lambda.prototype.valueOf = function(indent) {
	if (indent === undefined) {
		indent = '';
	}
	var nextindent = indent + '\t';
	var val = '';
	for (var i = 0; i < this.args.length; i++) {
		val += this.args[i].valueOf(indent) + ' ';
	}
	val += '{';
	for (var i = 0; i < this.expressions.length; i++) {
		val += '\n' + nextindent + this.expressions[i].valueOf(nextindent);
	}
	if (this.expressions.length) {
		val += '\n' + indent;
	}
	val += '}';
	return val;
};

function assignment(sym, expr)
{
	this.symbol = sym;
	this.expression = expr;
}
assignment.prototype.valueOf = function(indent) {
	return this.symbol.valueOf(indent) + ' <- ' + this.expression.valueOf(indent);
};

function isLambda(node)
{
	return node instanceof lambda;
}

var grammar =
'start = ws module:(object / lambda) ws { return module; };' +
'ws = ([ \\t\\n\\r] / "//" [^\\n]* "\\n")*;' +
'hws = ([ \\t] / "/*" ([^*] / "*" ! "/")* "*/" )*;' +
'expr = e:(funcall / methcall / assignment / opexpr) ws { return e; };' +
'opexpr = left:compareop pieces:(hws ("&&" / "||") ws compareop)* { if (pieces.length) { var cur = new op(left, pieces[0][1], pieces[0][3]); for (var i = 1; i < pieces.length; i++) { cur = new op(cur, pieces[i][1], pieces[i][3]); } return cur; } else { return left; } };'+
'compareop = left:maybecons pieces:(hws ("<=" / ">=" / "<" / ">" / "=" / "!=") ws maybecons)* { if (pieces.length) { var cur = new op(left, pieces[0][1], pieces[0][3]); for (var i = 1; i < pieces.length; i++) { cur = new op(cur, pieces[i][1], pieces[i][3]); } return cur; } else { return left; } };'+
'maybecons = consop / addsub;' +
'consop = left:addsub hws "|" ws right:maybecons { return new op(left, "|", right); };'+
'addsub = left:muldiv pieces:(hws ((("xor"/"and"/"or") ! [a-zA-Z_!?@0-9])/("+"/"-"/".")) ws muldiv)* { if (pieces.length) { var cur = new op(left, pieces[0][1], pieces[0][3]); for (var i = 1; i < pieces.length; i++) { cur = new op(cur, pieces[i][1], pieces[i][3]); } return cur; } else { return left; } };'+
'muldiv = left:primlitsym pieces:(hws ("*"/"/"/"%") ws primlitsym)* { if (pieces.length) { var cur = new op(left, pieces[0][1], pieces[0][3]); for (var i = 1; i < pieces.length; i++) { cur = new op(cur, pieces[i][1], pieces[i][3]); } return cur; } else { return left; } };'+
'primlitsym = hws val:(float / hex / binary / int / string / symbol / object / array / list / lambda / "(" ws expr:expr hws ")" { return expr; }) { return val; };' +
'symbol = chars:[a-zA-Z_!?@]+ trailing:(":"? [a-zA-Z_!?@0-9])* ! ":" { for (var i = 0; i < trailing.length; i++) { trailing[i] = trailing[i].join(""); } return new symbol(chars.join("") + trailing.join("")); };' +
'float = digits:[0-9]+ "." decimals:[0-9]+ { return new floatlit(parseFloat(digits.join("") + "." + decimals.join(""))); };' +
'binary = "0b" digits:[01]+ { return new intlit(parseInt(digits.join(""), 2)); };' +
'hex = "0x" digits:[0-9a-fA-F]+ size:([iu] ("8" / "16" / "32" / "64"))? { var bits = size ? parseInt(size[1], 10) : 0; return new intlit(parseInt(digits.join(""), 16), bits, size[0] == "u"); };' +
'int = sign:"-"? digits:[0-9]+ size:([iu] ("8" / "16" / "32" / "64"))? { var bits = size ? parseInt(size[1], 10) : 0; return new intlit(parseInt(sign + digits.join(""), 10), bits, size[0] == "u"); };' +
'string = "\\"" text:(strpart/escape)* "\\"" { return new strlit(text.join("")); };' +
'strpart = text:[^\\"\\\\]+ { return text.join(""); };' +
'escape = "\\\\" char:[nt\\"r\\\\] { if (char == "n") { return "\\n"; } if (char == "r") { return "\\r"; } if (char == "t") { return "\\t"; } return char; };' +
'object = "#{" ws messages:(assignment / funexpr)* "}" { return new object(messages); };' +
'array = "#[" ws els:expr* "]" { return new arraylit(els); };' +
'list = "[" ws els:expr* "]" { return new listlit(els); };' +
'opsym = name:("&&" / "||" / "<=" / ">=" / "<" / ">" / "=" / "!=" / "+" / "-" / "." / "*" / "/" / "%" / "|") { return new symbol(name); };' +
'assignment = ws sym:(opsym / symbol) hws "<-" expr:expr ws { return new assignment(sym, expr); }' +
'lambda = args:((& ":") argname+  )? "{" ws exprs:expr* "}" { return new lambda(args[1], exprs); };' +
'argname = init:":"? chars:[a-zA-Z_!?@]+ trailing:[a-zA-Z_!?@0-9]* hws { return new symbol(init + chars.join("") + trailing.join("")); };' +
'funexpr = f: funcall ws { return f; };' +
'funcall = hws parts: funcallpart+ { var fun = ""; var args = []; for (var i = 0; i < parts.length; i++) { fun += parts[i].name; args = args.concat(parts[i].args); } return new funcall(fun, args); };' +
'funcallpart = fun:funpart args:opexpr* hws { return { name: fun, args: args}; };' +
'funpart = chars:[a-zA-Z_!?@]+ middle:[a-zA-Z_!?@0-9]* ":" & [ \\t\\n\\r] { return chars.join("") + middle.join("") + ":"; };' +
'methcall = receiver:opexpr hws info:methcallrest { info.receiver = receiver; return info; };' +
'methcallrest = funcall / unarymeth;' +
'unarymeth = name:symbol { return new funcall(name.name, []); };';
var parser = PEG.buildParser(grammar);