{ var TOKEN = {
LITERAL:1, OPERATOR:2, COMPARE:3, LOGICAL:4, ASSIGN:5 } function TRUE(n) { return n===0 || !!n; }
function OP(c,h,t,opc,valc) {
if (!t.length) return h; opc = opc || 1; valc = valc || 3; var ret = [c,h]; t.forEach(function(n) { ret.push(n[opc]); ret.push(n[valc]); }) return ret; } function EVAL(nodes,ctx) { function E(n) { return EVAL(nodes[n],ctx); } if (!Array.isArray(nodes)) console.log(nodes); var tok = nodes[0]; switch (tok) { case TOKEN.LITERAL: return nodes[1]; case TOKEN.COMPARE: var cur = EVAL(nodes[1],ctx); var i = 2; while (i<nodes.length) { var op = nodes[i++]; var val = EVAL(nodes[i++],ctx); console.log(cur,op,val); switch (op) { case '<': if(!(cur<val)) return false; break; case '>': if(!(cur>val)) return false; break; case '<=': if(!(cur<=val)) return false; break; case '>=': if(!(cur>=val)) return false; break; case '!=': if(!(cur!==val)) return false; break; case '==': if(!(cur===val)) return false; break; } cur = val; } return true; case TOKEN.LOGICAL: var acc = EVAL(nodes[1],ctx); var i = 2; while (i<nodes.length) { var op = nodes[i++]; //var val = EVAL(nodes[i++],ctx); switch (op) { case '&&': if (!TRUE(acc)) return false; acc=EVAL(nodes[i++],ctx); break; case '||': if (TRUE(acc)) return acc; acc=EVAL(nodes[i++],ctx); break; } } return acc; case TOKEN.OPERATOR: var acc = EVAL(nodes[1],ctx); var i = 2; while (i<nodes.length) { var op = nodes[i++]; var val = EVAL(nodes[i++],ctx); switch (op) { case '+': acc+=val; break; case '-': acc-=val; break; case '*': acc*=val; break; case '/': acc/=val; break; case '%': acc%=val; break; case ';': case ',': acc=val; break; } }
return acc;
}
return "BAD TOKEN"
}
} program = e:statements { return [EVAL(e,{a:3}),e];} statements = h:statement t:(_ ';' _ statement)* ';'? { return OP('O',h,t)} statement = assign/expr assign = n:ident _ "=" _ e:expr { return ['A',n,e] } expr = or or = h:and t:( _ ("||") _ and)* { return OP(TOKEN.LOGICAL,h,t)} and = h:compare t:( _ ("&&") _ compare)* { return OP(TOKEN.LOGICAL,h,t)} compare = h:addsub t:( _ ("!="/"=="/"<="/">="/">"/"<") _ addsub)* { return OP(TOKEN.COMPARE,h,t)} addsub = h:muldiv t:( _ [+-] _ muldiv)* { return OP(TOKEN.OPERATOR,h,t)} muldiv = h:atom t:( _ [*/%] _ atom)* { return OP(TOKEN.OPERATOR,h,t)} atom = literal/path/brackets brackets = _ "(" _ e:expr _ ")" _ { return e} path = h:head t:( _ [.] _ key)* { return OP('P',h,t)} head = i:ident { return [i,'$']; }/brackets key = ident/digits/brackets
literal = boolean/number boolean = "true" eow { return [TOKEN.LITERAL,true]; } / "false" eow { return [TOKEN.LITERAL,false] } number = n:$( d:digits ('.' digits)? ([Ee] digits)?) { return [TOKEN.LITERAL,Number(n)]} digits = [0-9]+ ident = $([A-Z_]i [A-Z0-9_]i*) eow = ![a-z0-9i] _ = [ \n\r\t]* __ = [ \n\r\t]+