Mercurial > repos > tabletprog
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);