pavone@5: pavone@5: function op(left, op, right) pavone@5: { pavone@5: this.left = left; pavone@217: if (op instanceof Array) { pavone@217: op = op[0]; pavone@217: } pavone@5: this.op = op; pavone@5: this.right = right; pavone@5: } pavone@217: op.prototype.valueOf = function(indent) { pavone@217: return this.left.valueOf(indent) + ' ' + this.op.valueOf(indent) + ' ' + this.right.valueOf(indent); pavone@217: }; pavone@5: pavone@19: function symbol(name, symbols) pavone@5: { pavone@5: this.name = name; pavone@19: this.symbols = symbols; pavone@217: this.dirty = false; pavone@5: } pavone@6: symbol.prototype.cleanName = function() { pavone@6: return this.name[0] == ':' ? this.name.substr(1) : this.name; pavone@6: } pavone@217: symbol.prototype.valueOf = function() { pavone@217: return this.name; pavone@217: }; pavone@5: pavone@155: function intlit(val, bits, unsigned) pavone@5: { pavone@135: if (!bits) { pavone@135: bits = 32; pavone@135: } pavone@155: if (unsigned === undefined) { pavone@155: unsigned = false; pavone@155: } pavone@155: this.unsigned = unsigned; pavone@135: this.bits = bits; pavone@5: this.val = val; pavone@5: } pavone@217: intlit.prototype.valueOf = function() { pavone@217: var val = '' + this.val; pavone@217: if (this.bits != 32 || this.unsigned) { pavone@217: val += this.unsigned ? 'u' : 'i' pavone@217: val += this.bits; pavone@217: } pavone@217: return val; pavone@217: }; pavone@5: pavone@5: function floatlit(val) pavone@5: { pavone@5: this.val = val; pavone@5: } pavone@217: floatlit.prototype.valueOf = function() { pavone@217: return '' + val; pavone@217: }; pavone@5: pavone@5: function strlit(val) pavone@5: { pavone@5: this.val = val; pavone@5: } pavone@217: strlit.prototype.valueOf = function() { pavone@217: return '"'+this.val+'"'; pavone@217: }; pavone@5: pavone@25: function listlit(val) pavone@25: { pavone@25: this.val = val; pavone@25: } pavone@217: listlit.prototype.valueOf = function(indent) { pavone@217: if (indent === undefined) { pavone@217: indent = ''; pavone@217: } pavone@217: var nextindent = indent + '\t'; pavone@217: var val = '[' pavone@217: for (var i = 0; i < this.val.length; i++) { pavone@217: val += '\n' + nextindent + this.val[i].valueOf(nextindent); pavone@217: } pavone@217: if (this.val.length) { pavone@217: val += '\n' + indent; pavone@217: } pavone@217: val += ']'; pavone@217: return val; pavone@217: }; pavone@25: pavone@38: function arraylit(val) pavone@38: { pavone@38: this.val = val; pavone@38: } pavone@217: arraylit.prototype.valueOf = function(indent) { pavone@217: if (indent === undefined) { pavone@217: indent = ''; pavone@217: } pavone@217: var nextindent = indent + '\t'; pavone@217: var val = '#[' pavone@217: for (var i = 0; i < this.val.length; i++) { pavone@217: val += '\n' + nextindent + this.val[i].valueOf(nextindent); pavone@217: } pavone@217: if (this.val.length) { pavone@217: val += '\n' + indent; pavone@217: } pavone@217: val += ']'; pavone@217: return val; pavone@217: }; pavone@38: pavone@5: function funcall(name, args) pavone@5: { pavone@5: this.name = name; pavone@5: this.args = args; pavone@5: this.receiver = null; pavone@217: this.dirty = false; pavone@5: } pavone@217: funcall.prototype.valueOf = function(indent) { pavone@217: var parts = this.name.split(':'); pavone@217: var val = ''; pavone@217: if (this.receiver) { pavone@217: val += this.receiver.valueOf(indent); pavone@217: } pavone@217: var curarg = 0; pavone@217: for (var i = 0; i < parts.length; i++) { pavone@217: if (val) { pavone@217: val += ' '; pavone@217: } pavone@217: if (parts[i]) { pavone@217: val += parts[i] + ': '; pavone@217: } pavone@217: if (curarg < this.args.length) { pavone@217: val += this.args[curarg++].valueOf(indent); pavone@217: } pavone@217: } pavone@217: while (curarg < this.args.length) { pavone@217: val += ' ' + this.args[curarg++].valueOf(indent); pavone@217: } pavone@217: return val; pavone@217: }; pavone@5: pavone@5: function object(messages) pavone@5: { pavone@5: this.messages = messages; pavone@83: this.name = null; pavone@5: } pavone@217: object.prototype.valueOf = function(indent) { pavone@217: if (indent === undefined) { pavone@217: indent = ''; pavone@217: } pavone@217: var nextindent = indent + '\t'; pavone@217: var val = '#{'; pavone@217: for (var i = 0; i < this.messages.length; i++) { pavone@217: val += '\n' + nextindent + this.messages[i].valueOf(nextindent); pavone@217: } pavone@217: if (val.length > 2) { pavone@217: val += '\n' + indent; pavone@217: } pavone@217: val += '}'; pavone@217: return val; pavone@217: }; pavone@5: pavone@5: function lambda(args, expressions) pavone@5: { pavone@42: this.args = args ? args : []; pavone@5: this.expressions = expressions; pavone@5: } pavone@217: lambda.prototype.valueOf = function(indent) { pavone@217: if (indent === undefined) { pavone@217: indent = ''; pavone@217: } pavone@217: var nextindent = indent + '\t'; pavone@217: var val = ''; pavone@217: for (var i = 0; i < this.args.length; i++) { pavone@217: val += this.args[i].valueOf(indent) + ' '; pavone@217: } pavone@217: val += '{'; pavone@217: for (var i = 0; i < this.expressions.length; i++) { pavone@217: val += '\n' + nextindent + this.expressions[i].valueOf(nextindent); pavone@217: } pavone@217: if (this.expressions.length) { pavone@217: val += '\n' + indent; pavone@217: } pavone@217: val += '}'; pavone@217: return val; pavone@217: }; pavone@5: pavone@5: function assignment(sym, expr) pavone@5: { pavone@5: this.symbol = sym; pavone@5: this.expression = expr; pavone@5: } pavone@217: assignment.prototype.valueOf = function(indent) { pavone@217: return this.symbol.valueOf(indent) + ' <- ' + this.expression.valueOf(indent); pavone@217: }; pavone@1: pavone@25: function isLambda(node) pavone@25: { pavone@25: return node instanceof lambda; pavone@25: } pavone@25: pavone@122: var grammar = pavone@1: 'start = ws module:(object / lambda) ws { return module; };' + pavone@4: 'ws = ([ \\t\\n\\r] / "//" [^\\n]* "\\n")*;' + pavone@4: 'hws = ([ \\t] / "/*" ([^*] / "*" ! "/")* "*/" )*;' + pavone@214: 'expr = e:(funcall / methcall / assignment / opexpr) ws { return e; };' + pavone@229: '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; } };'+ pavone@229: '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; } };'+ pavone@170: 'maybecons = consop / addsub;' + pavone@229: 'consop = left:addsub hws "|" ws right:maybecons { return new op(left, "|", right); };'+ pavone@229: '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; } };'+ pavone@229: '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; } };'+ pavone@53: 'primlitsym = hws val:(float / hex / binary / int / string / symbol / object / array / list / lambda / "(" ws expr:expr hws ")" { return expr; }) { return val; };' + pavone@104: '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("")); };' + pavone@5: 'float = digits:[0-9]+ "." decimals:[0-9]+ { return new floatlit(parseFloat(digits.join("") + "." + decimals.join(""))); };' + pavone@49: 'binary = "0b" digits:[01]+ { return new intlit(parseInt(digits.join(""), 2)); };' + pavone@155: '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"); };' + pavone@155: '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"); };' + pavone@44: 'string = "\\"" text:(strpart/escape)* "\\"" { return new strlit(text.join("")); };' + pavone@122: 'strpart = text:[^\\"\\\\]+ { return text.join(""); };' + pavone@233: 'escape = "\\\\" char:[nt\\"r\\\\] { if (char == "n") { return "\\n"; } if (char == "r") { return "\\r"; } if (char == "t") { return "\\t"; } return char; };' + pavone@83: 'object = "#{" ws messages:(assignment / funexpr)* "}" { return new object(messages); };' + pavone@176: 'array = "#[" ws els:expr* "]" { return new arraylit(els); };' + pavone@176: 'list = "[" ws els:expr* "]" { return new listlit(els); };' + pavone@170: 'opsym = name:("&&" / "||" / "<=" / ">=" / "<" / ">" / "=" / "!=" / "+" / "-" / "." / "*" / "/" / "%" / "|") { return new symbol(name); };' + pavone@187: 'assignment = ws sym:(opsym / symbol) hws "<-" expr:expr ws { return new assignment(sym, expr); }' + pavone@214: 'lambda = args:((& ":") argname+ )? "{" ws exprs:expr* "}" { return new lambda(args[1], exprs); };' + pavone@5: 'argname = init:":"? chars:[a-zA-Z_!?@]+ trailing:[a-zA-Z_!?@0-9]* hws { return new symbol(init + chars.join("") + trailing.join("")); };' + pavone@83: 'funexpr = f: funcall ws { return f; };' + pavone@104: '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); };' + pavone@2: 'funcallpart = fun:funpart args:opexpr* hws { return { name: fun, args: args}; };' + pavone@2: 'funpart = chars:[a-zA-Z_!?@]+ middle:[a-zA-Z_!?@0-9]* ":" & [ \\t\\n\\r] { return chars.join("") + middle.join("") + ":"; };' + pavone@2: 'methcall = receiver:opexpr hws info:methcallrest { info.receiver = receiver; return info; };' + pavone@2: 'methcallrest = funcall / unarymeth;' + pavone@6: 'unarymeth = name:symbol { return new funcall(name.name, []); };'; pavone@0: var parser = PEG.buildParser(grammar); pavone@0: pavone@0: