diff --git a/index.js b/index.js index d8a328f..e4e9996 100644 --- a/index.js +++ b/index.js @@ -78,7 +78,7 @@ yy: {}, symbols_: {"error":2,"expressions":3,"e":4,"EOF":5,"OR":6,"AND":7,"NOT":8,"term":9,"=":10,"<>":11,"IN":12,"NOT_IN":13,">":14,">=":15,"<":16,"<=":17,"(":18,")":19,"NUMBER":20,"VARIABLE":21,"STRING":22,"ARRAY":23,"DATE":24,"$accept":0,"$end":1}, terminals_: {2:"error",5:"EOF",6:"OR",7:"AND",8:"NOT",10:"=",11:"<>",12:"IN",13:"NOT_IN",14:">",15:">=",16:"<",17:"<=",18:"(",19:")",20:"NUMBER",21:"VARIABLE",22:"STRING",23:"ARRAY",24:"DATE"}, productions_: [0,[3,2],[4,3],[4,3],[4,2],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[9,1],[9,1],[9,1],[9,1],[9,1]], -performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */, data, validator) { +performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */, data, validator, grammar) { /* this == yyval */ var $0 = $$.length - 1; @@ -87,37 +87,37 @@ case 1: return $$[$0-1]; break; case 2: -this.$ = $$[$0-2] || $$[$0]; +this.$ = !grammar ? ($$[$0-2] || $$[$0]) : [$$[$0-2], 'or', $$[$0]]; break; case 3: -this.$ = $$[$0-2] && $$[$0]; +this.$ = !grammar ? ($$[$0-2] && $$[$0]) : [$$[$0-2], 'and', $$[$0]]; break; case 4: -this.$ = !$$[$0]; +this.$ = !grammar ? !$$[$0] : [$$[$0], 'not', null]; break; case 5: -this.$ = $$[$0-2] === $$[$0]; +this.$ = !grammar ? ($$[$0-2] === $$[$0]) : [$$[$0-2], 'eq', $$[$0]]; break; case 6: -this.$ = $$[$0-2] !== $$[$0]; +this.$ = !grammar ? ($$[$0-2] !== $$[$0]) : [$$[$0-2], 'neq', $$[$0]]; break; case 7: -this.$ = validator ? validator.in($$[$0-2], $$[$0]) : $$[$0].indexOf($$[$0-2]) !== -1 +this.$ = validator ? validator.in($$[$0-2], $$[$0]) : (!grammar ? ($$[$0].indexOf($$[$0-2]) !== -1) : [$$[$0-2], 'in', $$[$0]]) break; case 8: -this.$ = validator ? validator.not_in($$[$0-2], $$[$0]) : $$[$0].indexOf($$[$0-2]) === -1 +this.$ = validator ? validator.not_in($$[$0-2], $$[$0]) : (!grammar ? ($$[$0].indexOf($$[$0-2]) === -1) : [$$[$0-2], 'nin', $$[$0]]) break; case 9: -this.$ = $$[$0-2] > $$[$0]; +this.$ = !grammar ? $$[$0-2] > $$[$0] : [$$[$0-2], 'gt', $$[$0]]; break; case 10: -this.$ = $$[$0-2] >= $$[$0]; +this.$ = !grammar ? $$[$0-2] >= $$[$0] : [$$[$0-2], 'gte', $$[$0]]; break; case 11: -this.$ = $$[$0-2] < $$[$0]; +this.$ = !grammar ? $$[$0-2] < $$[$0] : [$$[$0-2], 'lt', $$[$0]]; break; case 12: -this.$ = $$[$0-2] <= $$[$0]; +this.$ = !grammar ? $$[$0-2] <= $$[$0] : [$$[$0-2], 'lte', $$[$0]]; break; case 13: this.$ = $$[$0-1]; @@ -126,7 +126,7 @@ case 14: this.$ = validator ? validator.number(Number(yytext)) : Number(yytext); break; case 15: -this.$ = validator ? validator.variable(yytext, data) : data[yytext]; +this.$ = validator ? validator.variable(yytext, data) : !grammar ? data[yytext]: yytext; break; case 16: this.$ = validator ? validator.string(JSON.parse(yytext)) : JSON.parse(yytext); @@ -295,7 +295,45 @@ parse: function parse(input) { function splitArray(input){ return input.replace(/\[|\]+/g,'').split(',').map(function(item){return item ? JSON.parse(item.trim()): ''}); -}/* generated by jison-lex 0.3.4 */ +} + +function _g() { return typeof grammar === 'undefined'; } +function _v() { return typeof validator !== 'undefined'; } + +function isExpr(input) { + return Array.isArray(input) && input.length === 3; +} + +function toValue(input) { + if (input instanceof Date) return (input.getMonth() + 1) + '/' + input.getDate() + '/' + input.getFullYear(); + return JSON.stringify(input); +} + +function generate(input) { + var lhs = isExpr(input[0]) ? generate(input[0]) : input[0]; + var op = input[1]; + var rhs = isExpr(input[2]) ? generate(input[2]) : toValue(input[2]); + + var _s = function(str) { return str; }; + switch (op) { + case 'not' : return _s('!(' + lhs + ')'); + case 'eq' : return _s(lhs + ' = ' + rhs); + case 'neq' : return _s(lhs + ' <> ' + rhs); + case 'in' : return _s(lhs + ' in ' + rhs); + case 'nin' : return _s(lhs + ' not in ' + rhs); + case 'gt' : return _s(lhs + ' > ' + rhs); + case 'gte' : return _s(lhs + ' >= ' + rhs); + case 'lt' : return _s(lhs + ' < ' + rhs); + case 'lte' : return _s(lhs + ' <= ' + rhs); + case 'and' : return _s('(' + lhs + ' and ' + rhs + ')'); + case 'or' : return _s('(' + lhs + ' or ' + rhs + ')'); + default: + throw new Error('do not recognize:' + lhs + ', ' + op + ', ' + rhs); + } +} + +exports.generate = generate; +/* generated by jison-lex 0.3.4 */ var lexer = (function(){ var lexer = ({ diff --git a/rule.jison b/rule.jison index 939d4de..a918ff8 100644 --- a/rule.jison +++ b/rule.jison @@ -60,6 +60,7 @@ %start expressions %parse-param data %parse-param validator +%parse-param grammar %% /* language grammar */ @@ -70,27 +71,27 @@ expressions e : e OR e - {$$ = $1 || $3;} + {$$ = !grammar ? ($1 || $3) : [$1, 'or', $3];} | e AND e - {$$ = $1 && $3;} + {$$ = !grammar ? ($1 && $3) : [$1, 'and', $3];} | NOT e - {$$ = !$2;} + {$$ = !grammar ? !$2 : [$2, 'not', null];} | term '=' term - {$$ = $1 === $3;} + {$$ = !grammar ? ($1 === $3) : [$1, 'eq', $3];} | term '<>' term - {$$ = $1 !== $3;} + {$$ = !grammar ? ($1 !== $3) : [$1, 'neq', $3];} | term IN term - {$$ = validator ? validator.in($1, $3) : $3.indexOf($1) !== -1} + {$$ = validator ? validator.in($1, $3) : (!grammar ? ($3.indexOf($1) !== -1) : [$1, 'in', $3])} | term NOT_IN term - {$$ = validator ? validator.not_in($1, $3) : $3.indexOf($1) === -1} + {$$ = validator ? validator.not_in($1, $3) : (!grammar ? ($3.indexOf($1) === -1) : [$1, 'nin', $3])} | term '>' term - {$$ = $1 > $3;} + {$$ = !grammar ? $1 > $3 : [$1, 'gt', $3];} | term '>=' term - {$$ = $1 >= $3;} + {$$ = !grammar ? $1 >= $3 : [$1, 'gte', $3];} | term '<' term - {$$ = $1 < $3;} + {$$ = !grammar ? $1 < $3 : [$1, 'lt', $3];} | term '<=' term - {$$ = $1 <= $3;} + {$$ = !grammar ? $1 <= $3 : [$1, 'lte', $3];} | '(' e ')' {$$ = $2;} ; @@ -99,7 +100,7 @@ term : NUMBER {$$ = validator ? validator.number(Number(yytext)) : Number(yytext);} | VARIABLE - {$$ = validator ? validator.variable(yytext, data) : data[yytext];} + {$$ = validator ? validator.variable(yytext, data) : !grammar ? data[yytext]: yytext;} | STRING {$$ = validator ? validator.string(JSON.parse(yytext)) : JSON.parse(yytext);} | ARRAY @@ -112,4 +113,41 @@ term function splitArray(input){ return input.replace(/\[|\]+/g,'').split(',').map(function(item){return item ? JSON.parse(item.trim()): ''}); -} \ No newline at end of file +} + +function _g() { return typeof grammar === 'undefined'; } +function _v() { return typeof validator !== 'undefined'; } + +function isExpr(input) { + return Array.isArray(input) && input.length === 3; +} + +function toValue(input) { + if (input instanceof Date) return (input.getMonth() + 1) + '/' + input.getDate() + '/' + input.getFullYear(); + return JSON.stringify(input); +} + +function generate(input) { + var lhs = isExpr(input[0]) ? generate(input[0]) : input[0]; + var op = input[1]; + var rhs = isExpr(input[2]) ? generate(input[2]) : toValue(input[2]); + + var _s = function(str) { return str; }; + switch (op) { + case 'not' : return _s('!(' + lhs + ')'); + case 'eq' : return _s(lhs + ' = ' + rhs); + case 'neq' : return _s(lhs + ' <> ' + rhs); + case 'in' : return _s(lhs + ' in ' + rhs); + case 'nin' : return _s(lhs + ' not in ' + rhs); + case 'gt' : return _s(lhs + ' > ' + rhs); + case 'gte' : return _s(lhs + ' >= ' + rhs); + case 'lt' : return _s(lhs + ' < ' + rhs); + case 'lte' : return _s(lhs + ' <= ' + rhs); + case 'and' : return _s('(' + lhs + ' and ' + rhs + ')'); + case 'or' : return _s('(' + lhs + ' or ' + rhs + ')'); + default: + throw new Error('do not recognize:' + lhs + ', ' + op + ', ' + rhs); + } +} + +exports.generate = generate;