diff --git a/dist/browser/filtrex.js b/dist/browser/filtrex.js index 05888cd..df058e3 100644 --- a/dist/browser/filtrex.js +++ b/dist/browser/filtrex.js @@ -116,106 +116,106 @@ var filtrex = (function (exports) { case 1: return $$[$0 - 1]; case 2: - this.$ = ["(", $$[$0 - 2], "+", $$[$0], ")"]; + this.$ = ["(", "", $$[$0 - 2], " + ", $$[$0], "", ")"]; break; case 3: - this.$ = ["(", $$[$0 - 2], "-", $$[$0], ")"]; + this.$ = ["(", "", $$[$0 - 2], " - ", $$[$0], "", ")"]; break; case 4: - this.$ = ["(", $$[$0 - 2], "*", $$[$0], ")"]; + this.$ = ["(", "", $$[$0 - 2], " * ", $$[$0], "", ")"]; break; case 5: - this.$ = ["(", $$[$0 - 2], "/", $$[$0], ")"]; + this.$ = ["(", "", $$[$0 - 2], " / ", $$[$0], "", ")"]; break; case 6: - this.$ = ["(", $$[$0 - 2], "%", $$[$0], ")"]; + this.$ = ["(", "", $$[$0 - 2], " % ", $$[$0], "", ")"]; break; case 7: - this.$ = ["(", "Math.pow(", $$[$0 - 2], ",", $$[$0], ")", ")"]; + this.$ = ["(", "Math.pow( ", $$[$0 - 2], ", ", $$[$0], " )", ")"]; break; case 8: - this.$ = ["(", "-", $$[$0], ")"]; + this.$ = ["(", "- ", $$[$0], "", ")"]; break; case 9: - this.$ = ["(", "Number(", $$[$0 - 2], "&&", $$[$0], ")", ")"]; + this.$ = ["(", "", "std.coerceBoolean", "(", $$[$0 - 2], ") && ", "std.coerceBoolean", "(", $$[$0], ")", ")"]; break; case 10: - this.$ = ["(", "Number(", $$[$0 - 2], "||", $$[$0], ")", ")"]; + this.$ = ["(", "", "std.coerceBoolean", "(", $$[$0 - 2], ") || ", "std.coerceBoolean", "(", $$[$0], ")", ")"]; break; case 11: - this.$ = ["(", "Number(!", $$[$0], ")", ")"]; + this.$ = ["(", "! ", "std.coerceBoolean", "(", $$[$0], ")", ")"]; break; case 12: - this.$ = ["(", "Number(", $$[$0 - 2], "==", $$[$0], ")", ")"]; + this.$ = ["(", "", $$[$0 - 2], " === ", $$[$0], "", ")"]; break; case 13: - this.$ = ["(", "Number(", $$[$0 - 2], "!=", $$[$0], ")", ")"]; + this.$ = ["(", "", $$[$0 - 2], " !== ", $$[$0], "", ")"]; break; case 14: - this.$ = ["(", "Number(RegExp(", $$[$0], ").test(", $$[$0 - 2], "))", ")"]; + this.$ = ["(", "RegExp(", $$[$0], ").test(", $$[$0 - 2], ")", ")"]; break; case 15: - this.$ = ["(", "Number(", $$[$0 - 2], "<", $$[$0], ")", ")"]; + this.$ = ["(", "", $$[$0 - 2], " < ", $$[$0], "", ")"]; break; case 16: - this.$ = ["(", "Number(", $$[$0 - 2], "<=", $$[$0], ")", ")"]; + this.$ = ["(", "", $$[$0 - 2], " <= ", $$[$0], "", ")"]; break; case 17: - this.$ = ["(", "Number(", $$[$0 - 2], "> ", $$[$0], ")", ")"]; + this.$ = ["(", "", $$[$0 - 2], " > ", $$[$0], "", ")"]; break; case 18: - this.$ = ["(", "Number(", $$[$0 - 2], ">=", $$[$0], ")", ")"]; + this.$ = ["(", "", $$[$0 - 2], " >= ", $$[$0], "", ")"]; break; case 19: - this.$ = ["(", $$[$0 - 4], "?", $$[$0 - 2], ":", $$[$0], ")"]; + this.$ = ["(", "", $$[$0 - 4], " ? ", $$[$0 - 2], " : ", $$[$0], "", ")"]; break; case 20: - this.$ = ["(", $$[$0 - 1], ")"]; + this.$ = ["(", "", $$[$0 - 1], "", ")"]; break; case 21: - this.$ = ["(", "[", $$[$0 - 3], ",", $$[$0 - 1], "]", ")"]; + this.$ = ["(", "[ ", $$[$0 - 3], ", ", $$[$0 - 1], " ]", ")"]; break; case 22: - this.$ = ["(", $$[$0], ")"]; + this.$ = ["(", "", $$[$0], "", ")"]; break; case 23: - this.$ = ["(", $$[$0], ")"]; + this.$ = ["(", "", $$[$0], "", ")"]; break; case 24: this.$ = ["(", "prop(", $$[$0], ", data)", ")"]; break; case 25: - this.$ = ["(", "prop(", $$[$0 - 2], ",", $$[$0], ")", ")"]; + this.$ = ["(", "prop(", $$[$0 - 2], ", ", $$[$0], ")", ")"]; break; case 26: - this.$ = ["(", "(std.isfn(fns, ", $$[$0 - 2], ") ? fns[", $$[$0 - 2], "]() : std.unknown(", $$[$0 - 2], "))", ")"]; + this.$ = ["(", "std.isfn(fns, ", $$[$0 - 2], ") ? fns[", $$[$0 - 2], "]() : std.unknown(", $$[$0 - 2], ")", ")"]; break; case 27: - this.$ = ["(", "(std.isfn(fns, ", $$[$0 - 3], ") ? fns[", $$[$0 - 3], "](", $$[$0 - 1], ") : std.unknown(", $$[$0 - 3], "))", ")"]; + this.$ = ["(", "std.isfn(fns, ", $$[$0 - 3], ") ? fns[", $$[$0 - 3], "](", $$[$0 - 1], ") : std.unknown(", $$[$0 - 3], ")", ")"]; break; case 28: this.$ = ["(", "std.isSubset(", $$[$0 - 2], ", ", $$[$0], ")", ")"]; break; case 29: - this.$ = ["(", "+!std.isSubset(", $$[$0 - 3], ", ", $$[$0], ")", ")"]; + this.$ = ["(", "!std.isSubset(", $$[$0 - 3], ", ", $$[$0], ")", ")"]; break; case 30: - this.$ = [$$[$0]]; + this.$ = ["", $$[$0], ""]; break; case 31: - this.$ = [$$[$0 - 2], ",", $$[$0]]; + this.$ = ["", $$[$0 - 2], ", ", $$[$0], ""]; break; case 32: - this.$ = ["o ==", $$[$0]]; + this.$ = ["o === ", $$[$0], ""]; break; case 33: - this.$ = [$$[$0 - 2], "|| o ==", $$[$0]]; + this.$ = ["", $$[$0 - 2], " || o === ", $$[$0], ""]; break; case 34: - this.$ = ["(", $$[$0], ")"]; + this.$ = ["", $$[$0], ""]; break; case 35: - this.$ = [$$[$0 - 2], ",", $$[$0]]; + this.$ = ["", $$[$0 - 2], ", ", $$[$0], ""]; break; } }, @@ -1690,6 +1690,56 @@ var filtrex = (function (exports) { const parser = _parser; _parser.Parser; + /** + * Determines whether an object has a property with the specified name. + * @param {object} obj the object to be checked + * @param {string|number} prop property name + */ + function hasOwnProperty(obj, prop) { + if (typeof obj === "object" || typeof obj === "function") { + return Object.prototype.hasOwnProperty.call(obj, prop) + } + + return false + } + + /** + * Safe getter for `v[Symbol.toPrimitive]`. + */ + const _toPrimitive = + typeof Symbol !== "function" || typeof Symbol.toPrimitive !== "symbol" + ? () => undefined + : (v) => { + if (typeof v[Symbol.toPrimitive] === "function") { + return v[Symbol.toPrimitive] + } + + return undefined + }; + + /** + * Attempt to convert an object to the required primitive type. + * @param {object} obj + * @param {"string"|"number"|"bigint"} type + * @returns {string|number|bigint|undefined} + */ + function toPrimitive(obj, type) { + if (typeof obj !== "object" || typeof obj !== "function") { + return undefined + } + + try { + let val = _toPrimitive(obj)(type); + if (typeof val === type) return val + + val = obj.valueOf(); + if (typeof val === type) return val + + } finally { + return undefined + } + } + // the parser is dynamically generated from generateParser.js at compile time // Shared utility functions @@ -1697,31 +1747,57 @@ var filtrex = (function (exports) { { isfn: function(fns, funcName) { - return fns.hasOwnProperty(funcName) && typeof fns[funcName] === "function"; + return hasOwnProperty(fns, funcName) && typeof fns[funcName] === "function"; }, unknown: function(funcName) { - throw ReferenceError('Unknown function: ' + funcName + '()'); + throw new ReferenceError('Unknown function: ' + funcName + '()'); }, coerceArray: function(value) { - if (Array.isArray(value)) + if (value === undefined || value === null) { + throw new TypeError(`Expected a list, but got ${value} instead.`) + } + + if (Array.isArray(value)) { return value; - else + } else { return [value]; + } + }, + + coerceNumber: function (value) { + const origValue = value; + + if (value === undefined || value === null) + throw new TypeError(`Expected a numeric value, but got ${value} instead.`) + + if (Array.isArray(value) && value.length === 1) + value = value[0]; + + if (typeof value === 'object') + value = toPrimitive(value); + + if (typeof value === 'number' || typeof value === 'bigint') + return value; + + throw new TypeError(`Expected a numeric value, but got an ${typeof origValue} instead.`) }, coerceBoolean: function(value) { if (typeof value === 'boolean') - return +value; - else - return value; + return value + + if (typeof value === 'object' && value instanceof Boolean) + return value.valueOf(); + + throw new TypeError(`Expected a boolean (“true” or “false”) value, but got an ${typeof value} instead.`) }, isSubset: function(a, b) { const A = std.coerceArray(a); const B = std.coerceArray(b); - return +A.every( val => B.includes(val) ); + return A.every( val => B.includes(val) ); }, buildString: function(quote, literal) @@ -1797,11 +1873,13 @@ var filtrex = (function (exports) { random: Math.random, round: Math.round, sqrt: Math.sqrt, + exists: (v) => v !== undefined && v !== null, + empty: (v) => v === undefined || v === null || v === '' || Array.isArray(v) && v.length === 0 }; if (extraFunctions) { for (var name in extraFunctions) { - if (extraFunctions.hasOwnProperty(name)) { + if (hasOwnProperty(extraFunctions, name)) { functions[name] = extraFunctions[name]; } } @@ -1830,17 +1908,17 @@ var filtrex = (function (exports) { // Metaprogramming functions function prop(name, obj) { - return Object.prototype.hasOwnProperty.call(obj||{}, name) ? obj[name] : undefined; + return hasOwnProperty(obj||{}, name) ? obj[name] : undefined; } function safeGetter(obj) { return function get(name) { - return Object.prototype.hasOwnProperty.call(obj||{}, name) ? obj[name] : undefined; + return hasOwnProperty(obj||{}, name) ? obj[name] : undefined; } } if (typeof customProp === 'function') { - prop = (name, obj) => std.coerceBoolean(customProp(name, safeGetter(obj), obj)); + prop = (name, obj) => customProp(name, safeGetter(obj), obj); } diff --git a/dist/browser/filtrex.min.js b/dist/browser/filtrex.min.js index 1f0e819..44352fb 100644 --- a/dist/browser/filtrex.min.js +++ b/dist/browser/filtrex.min.js @@ -1 +1 @@ -var filtrex=function(t){"use strict";var e=function(){var t={trace:function(){},yy:{},symbols_:{error:2,expressions:3,e:4,EOF:5,"+":6,"-":7,"*":8,"/":9,"%":10,"^":11,and:12,or:13,not:14,"==":15,"!=":16,"~=":17,"<":18,"<=":19,">":20,">=":21,"?":22,":":23,"(":24,")":25,array:26,",":27,NUMBER:28,STRING:29,SYMBOL:30,of:31,argsList:32,in:33,inSet:34,$accept:0,$end:1},terminals_:{2:"error",5:"EOF",6:"+",7:"-",8:"*",9:"/",10:"%",11:"^",12:"and",13:"or",14:"not",15:"==",16:"!=",17:"~=",18:"<",19:"<=",20:">",21:">=",22:"?",23:":",24:"(",25:")",27:",",28:"NUMBER",29:"STRING",30:"SYMBOL",31:"of",33:"in"},productions_:[0,[3,2],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,2],[4,3],[4,3],[4,2],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,5],[4,3],[4,5],[4,1],[4,1],[4,1],[4,3],[4,3],[4,4],[4,3],[4,4],[32,1],[32,3],[34,1],[34,3],[26,1],[26,3]],performAction:function(t,e,n,r,s,i,o){var h=i.length-1;switch(s){case 1:return i[h-1];case 2:this.$=["(",i[h-2],"+",i[h],")"];break;case 3:this.$=["(",i[h-2],"-",i[h],")"];break;case 4:this.$=["(",i[h-2],"*",i[h],")"];break;case 5:this.$=["(",i[h-2],"/",i[h],")"];break;case 6:this.$=["(",i[h-2],"%",i[h],")"];break;case 7:this.$=["(","Math.pow(",i[h-2],",",i[h],")",")"];break;case 8:this.$=["(","-",i[h],")"];break;case 9:this.$=["(","Number(",i[h-2],"&&",i[h],")",")"];break;case 10:this.$=["(","Number(",i[h-2],"||",i[h],")",")"];break;case 11:this.$=["(","Number(!",i[h],")",")"];break;case 12:this.$=["(","Number(",i[h-2],"==",i[h],")",")"];break;case 13:this.$=["(","Number(",i[h-2],"!=",i[h],")",")"];break;case 14:this.$=["(","Number(RegExp(",i[h],").test(",i[h-2],"))",")"];break;case 15:this.$=["(","Number(",i[h-2],"<",i[h],")",")"];break;case 16:this.$=["(","Number(",i[h-2],"<=",i[h],")",")"];break;case 17:this.$=["(","Number(",i[h-2],"> ",i[h],")",")"];break;case 18:this.$=["(","Number(",i[h-2],">=",i[h],")",")"];break;case 19:this.$=["(",i[h-4],"?",i[h-2],":",i[h],")"];break;case 20:this.$=["(",i[h-1],")"];break;case 21:this.$=["(","[",i[h-3],",",i[h-1],"]",")"];break;case 22:case 23:this.$=["(",i[h],")"];break;case 24:this.$=["(","prop(",i[h],", data)",")"];break;case 25:this.$=["(","prop(",i[h-2],",",i[h],")",")"];break;case 26:this.$=["(","(std.isfn(fns, ",i[h-2],") ? fns[",i[h-2],"]() : std.unknown(",i[h-2],"))",")"];break;case 27:this.$=["(","(std.isfn(fns, ",i[h-3],") ? fns[",i[h-3],"](",i[h-1],") : std.unknown(",i[h-3],"))",")"];break;case 28:this.$=["(","std.isSubset(",i[h-2],", ",i[h],")",")"];break;case 29:this.$=["(","+!std.isSubset(",i[h-3],", ",i[h],")",")"];break;case 30:this.$=[i[h]];break;case 31:this.$=[i[h-2],",",i[h]];break;case 32:this.$=["o ==",i[h]];break;case 33:this.$=[i[h-2],"|| o ==",i[h]];break;case 34:this.$=["(",i[h],")"];break;case 35:this.$=[i[h-2],",",i[h]]}},table:[{3:1,4:2,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{1:[3]},{5:[1,9],6:[1,10],7:[1,11],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[1,16],13:[1,17],14:[1,27],15:[1,18],16:[1,19],17:[1,20],18:[1,21],19:[1,22],20:[1,23],21:[1,24],22:[1,25],33:[1,26]},{4:28,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:29,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:30,7:[1,3],14:[1,4],24:[1,5],26:31,28:[1,6],29:[1,7],30:[1,8]},{5:[2,22],6:[2,22],7:[2,22],8:[2,22],9:[2,22],10:[2,22],11:[2,22],12:[2,22],13:[2,22],14:[2,22],15:[2,22],16:[2,22],17:[2,22],18:[2,22],19:[2,22],20:[2,22],21:[2,22],22:[2,22],23:[2,22],25:[2,22],27:[2,22],33:[2,22]},{5:[2,23],6:[2,23],7:[2,23],8:[2,23],9:[2,23],10:[2,23],11:[2,23],12:[2,23],13:[2,23],14:[2,23],15:[2,23],16:[2,23],17:[2,23],18:[2,23],19:[2,23],20:[2,23],21:[2,23],22:[2,23],23:[2,23],25:[2,23],27:[2,23],33:[2,23]},{5:[2,24],6:[2,24],7:[2,24],8:[2,24],9:[2,24],10:[2,24],11:[2,24],12:[2,24],13:[2,24],14:[2,24],15:[2,24],16:[2,24],17:[2,24],18:[2,24],19:[2,24],20:[2,24],21:[2,24],22:[2,24],23:[2,24],24:[1,33],25:[2,24],27:[2,24],31:[1,32],33:[2,24]},{1:[2,1]},{4:34,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:35,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:36,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:37,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:38,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:39,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:40,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:41,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:42,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:43,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:44,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:45,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:46,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:47,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:48,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:49,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:50,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{33:[1,51]},{5:[2,8],6:[2,8],7:[2,8],8:[2,8],9:[2,8],10:[2,8],11:[2,8],12:[2,8],13:[2,8],14:[2,8],15:[2,8],16:[2,8],17:[2,8],18:[2,8],19:[2,8],20:[2,8],21:[2,8],22:[2,8],23:[2,8],25:[2,8],27:[2,8],33:[2,8]},{5:[2,11],6:[2,11],7:[2,11],8:[2,11],9:[2,11],10:[2,11],11:[2,11],12:[2,11],13:[2,11],14:[2,11],15:[2,11],16:[2,11],17:[2,11],18:[2,11],19:[2,11],20:[2,11],21:[2,11],22:[2,11],23:[2,11],25:[2,11],27:[2,11],33:[2,11]},{6:[1,10],7:[1,11],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[1,16],13:[1,17],14:[1,27],15:[1,18],16:[1,19],17:[1,20],18:[1,21],19:[1,22],20:[1,23],21:[1,24],22:[1,25],25:[1,52],27:[2,34],33:[1,26]},{27:[1,53]},{4:54,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:57,7:[1,3],14:[1,4],24:[1,5],25:[1,55],28:[1,6],29:[1,7],30:[1,8],32:56},{5:[2,2],6:[2,2],7:[2,2],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[2,2],13:[2,2],14:[1,27],15:[2,2],16:[2,2],17:[2,2],18:[2,2],19:[2,2],20:[2,2],21:[2,2],22:[2,2],23:[2,2],25:[2,2],27:[2,2],33:[2,2]},{5:[2,3],6:[2,3],7:[2,3],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[2,3],13:[2,3],14:[1,27],15:[2,3],16:[2,3],17:[2,3],18:[2,3],19:[2,3],20:[2,3],21:[2,3],22:[2,3],23:[2,3],25:[2,3],27:[2,3],33:[2,3]},{5:[2,4],6:[2,4],7:[2,4],8:[2,4],9:[2,4],10:[2,4],11:[1,15],12:[2,4],13:[2,4],14:[1,27],15:[2,4],16:[2,4],17:[2,4],18:[2,4],19:[2,4],20:[2,4],21:[2,4],22:[2,4],23:[2,4],25:[2,4],27:[2,4],33:[2,4]},{5:[2,5],6:[2,5],7:[2,5],8:[2,5],9:[2,5],10:[2,5],11:[1,15],12:[2,5],13:[2,5],14:[1,27],15:[2,5],16:[2,5],17:[2,5],18:[2,5],19:[2,5],20:[2,5],21:[2,5],22:[2,5],23:[2,5],25:[2,5],27:[2,5],33:[2,5]},{5:[2,6],6:[2,6],7:[2,6],8:[2,6],9:[2,6],10:[2,6],11:[1,15],12:[2,6],13:[2,6],14:[1,27],15:[2,6],16:[2,6],17:[2,6],18:[2,6],19:[2,6],20:[2,6],21:[2,6],22:[2,6],23:[2,6],25:[2,6],27:[2,6],33:[2,6]},{5:[2,7],6:[2,7],7:[2,7],8:[2,7],9:[2,7],10:[2,7],11:[2,7],12:[2,7],13:[2,7],14:[1,27],15:[2,7],16:[2,7],17:[2,7],18:[2,7],19:[2,7],20:[2,7],21:[2,7],22:[2,7],23:[2,7],25:[2,7],27:[2,7],33:[2,7]},{5:[2,9],6:[1,10],7:[1,11],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[2,9],13:[2,9],14:[1,27],15:[1,18],16:[1,19],17:[1,20],18:[1,21],19:[1,22],20:[1,23],21:[1,24],22:[2,9],23:[2,9],25:[2,9],27:[2,9],33:[1,26]},{5:[2,10],6:[1,10],7:[1,11],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[1,16],13:[2,10],14:[1,27],15:[1,18],16:[1,19],17:[1,20],18:[1,21],19:[1,22],20:[1,23],21:[1,24],22:[2,10],23:[2,10],25:[2,10],27:[2,10],33:[1,26]},{5:[2,12],6:[1,10],7:[1,11],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[2,12],13:[2,12],14:[1,27],15:[2,12],16:[2,12],17:[2,12],18:[1,21],19:[1,22],20:[1,23],21:[1,24],22:[2,12],23:[2,12],25:[2,12],27:[2,12],33:[2,12]},{5:[2,13],6:[1,10],7:[1,11],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[2,13],13:[2,13],14:[1,27],15:[2,13],16:[2,13],17:[2,13],18:[1,21],19:[1,22],20:[1,23],21:[1,24],22:[2,13],23:[2,13],25:[2,13],27:[2,13],33:[2,13]},{5:[2,14],6:[1,10],7:[1,11],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[2,14],13:[2,14],14:[1,27],15:[2,14],16:[2,14],17:[2,14],18:[1,21],19:[1,22],20:[1,23],21:[1,24],22:[2,14],23:[2,14],25:[2,14],27:[2,14],33:[2,14]},{5:[2,15],6:[1,10],7:[1,11],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[2,15],13:[2,15],14:[1,27],15:[2,15],16:[2,15],17:[2,15],18:[2,15],19:[2,15],20:[2,15],21:[2,15],22:[2,15],23:[2,15],25:[2,15],27:[2,15],33:[2,15]},{5:[2,16],6:[1,10],7:[1,11],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[2,16],13:[2,16],14:[1,27],15:[2,16],16:[2,16],17:[2,16],18:[2,16],19:[2,16],20:[2,16],21:[2,16],22:[2,16],23:[2,16],25:[2,16],27:[2,16],33:[2,16]},{5:[2,17],6:[1,10],7:[1,11],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[2,17],13:[2,17],14:[1,27],15:[2,17],16:[2,17],17:[2,17],18:[2,17],19:[2,17],20:[2,17],21:[2,17],22:[2,17],23:[2,17],25:[2,17],27:[2,17],33:[2,17]},{5:[2,18],6:[1,10],7:[1,11],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[2,18],13:[2,18],14:[1,27],15:[2,18],16:[2,18],17:[2,18],18:[2,18],19:[2,18],20:[2,18],21:[2,18],22:[2,18],23:[2,18],25:[2,18],27:[2,18],33:[2,18]},{6:[1,10],7:[1,11],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[1,16],13:[1,17],14:[1,27],15:[1,18],16:[1,19],17:[1,20],18:[1,21],19:[1,22],20:[1,23],21:[1,24],22:[1,25],23:[1,58],33:[1,26]},{5:[2,28],6:[1,10],7:[1,11],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[2,28],13:[2,28],14:[1,27],15:[1,18],16:[1,19],17:[1,20],18:[1,21],19:[1,22],20:[1,23],21:[1,24],22:[2,28],23:[2,28],25:[2,28],27:[2,28],33:[2,28]},{4:59,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{5:[2,20],6:[2,20],7:[2,20],8:[2,20],9:[2,20],10:[2,20],11:[2,20],12:[2,20],13:[2,20],14:[2,20],15:[2,20],16:[2,20],17:[2,20],18:[2,20],19:[2,20],20:[2,20],21:[2,20],22:[2,20],23:[2,20],25:[2,20],27:[2,20],33:[2,20]},{4:60,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{5:[2,25],6:[2,25],7:[2,25],8:[2,25],9:[2,25],10:[2,25],11:[2,25],12:[2,25],13:[2,25],14:[2,25],15:[2,25],16:[2,25],17:[2,25],18:[2,25],19:[2,25],20:[2,25],21:[2,25],22:[2,25],23:[2,25],25:[2,25],27:[2,25],33:[2,25]},{5:[2,26],6:[2,26],7:[2,26],8:[2,26],9:[2,26],10:[2,26],11:[2,26],12:[2,26],13:[2,26],14:[2,26],15:[2,26],16:[2,26],17:[2,26],18:[2,26],19:[2,26],20:[2,26],21:[2,26],22:[2,26],23:[2,26],25:[2,26],27:[2,26],33:[2,26]},{25:[1,61],27:[1,62]},{6:[1,10],7:[1,11],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[1,16],13:[1,17],14:[1,27],15:[1,18],16:[1,19],17:[1,20],18:[1,21],19:[1,22],20:[1,23],21:[1,24],22:[1,25],25:[2,30],27:[2,30],33:[1,26]},{4:63,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{5:[2,29],6:[2,29],7:[2,29],8:[2,29],9:[2,29],10:[2,29],11:[2,29],12:[2,29],13:[2,29],14:[2,29],15:[2,29],16:[2,29],17:[2,29],18:[2,29],19:[2,29],20:[2,29],21:[2,29],22:[2,29],23:[2,29],25:[2,29],27:[2,29],33:[2,29]},{6:[1,10],7:[1,11],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[1,16],13:[1,17],14:[1,27],15:[1,18],16:[1,19],17:[1,20],18:[1,21],19:[1,22],20:[1,23],21:[1,24],22:[1,25],25:[1,64],27:[2,35],33:[1,26]},{5:[2,27],6:[2,27],7:[2,27],8:[2,27],9:[2,27],10:[2,27],11:[2,27],12:[2,27],13:[2,27],14:[2,27],15:[2,27],16:[2,27],17:[2,27],18:[2,27],19:[2,27],20:[2,27],21:[2,27],22:[2,27],23:[2,27],25:[2,27],27:[2,27],33:[2,27]},{4:65,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{5:[2,19],6:[1,10],7:[1,11],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[1,16],13:[1,17],14:[1,27],15:[1,18],16:[1,19],17:[1,20],18:[1,21],19:[1,22],20:[1,23],21:[1,24],22:[2,19],23:[2,19],25:[2,19],27:[2,19],33:[1,26]},{5:[2,21],6:[2,21],7:[2,21],8:[2,21],9:[2,21],10:[2,21],11:[2,21],12:[2,21],13:[2,21],14:[2,21],15:[2,21],16:[2,21],17:[2,21],18:[2,21],19:[2,21],20:[2,21],21:[2,21],22:[2,21],23:[2,21],25:[2,21],27:[2,21],33:[2,21]},{6:[1,10],7:[1,11],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[1,16],13:[1,17],14:[1,27],15:[1,18],16:[1,19],17:[1,20],18:[1,21],19:[1,22],20:[1,23],21:[1,24],22:[1,25],25:[2,31],27:[2,31],33:[1,26]}],defaultActions:{9:[2,1]},parseError:function(t,e){throw new Error(t)},parse:function(t){var e=this,n=[0],r=[null],s=[],i=this.table,o="",h=0,a=0,l=0;this.lexer.setInput(t),this.lexer.yy=this.yy,this.yy.lexer=this.lexer,this.yy.parser=this,void 0===this.lexer.yylloc&&(this.lexer.yylloc={});var c=this.lexer.yylloc;s.push(c);var u=this.lexer.options&&this.lexer.options.ranges;function y(){var t;return"number"!=typeof(t=e.lexer.lex()||1)&&(t=e.symbols_[t]||t),t}"function"==typeof this.yy.parseError&&(this.parseError=this.yy.parseError);for(var f,p,g,m,b,d,x,_,k,w,$={};;){if(g=n[n.length-1],this.defaultActions[g]?m=this.defaultActions[g]:(null==f&&(f=y()),m=i[g]&&i[g][f]),void 0===m||!m.length||!m[0]){var E="";if(!l){for(d in k=[],i[g])this.terminals_[d]&&d>2&&k.push("'"+this.terminals_[d]+"'");E=this.lexer.showPosition?"Parse error on line "+(h+1)+":\n"+this.lexer.showPosition()+"\nExpecting "+k.join(", ")+", got '"+(this.terminals_[f]||f)+"'":"Parse error on line "+(h+1)+": Unexpected "+(1==f?"end of input":"'"+(this.terminals_[f]||f)+"'"),this.parseError(E,{text:this.lexer.match,token:this.terminals_[f]||f,line:this.lexer.yylineno,loc:c,expected:k})}if(3==l){if(1==f)throw new Error(E||"Parsing halted.");a=this.lexer.yyleng,o=this.lexer.yytext,h=this.lexer.yylineno,c=this.lexer.yylloc,f=y()}for(;!(2..toString()in i[g]);){if(0===g)throw new Error(E||"Parsing halted.");w=1,n.length=n.length-2*w,r.length=r.length-w,s.length=s.length-w,g=n[n.length-1]}p=2==f?null:f,f=2,m=i[g=n[n.length-1]]&&i[g][2],l=3}if(m[0]instanceof Array&&m.length>1)throw new Error("Parse Error: multiple actions possible at state: "+g+", token: "+f);switch(m[0]){case 1:n.push(f),r.push(this.lexer.yytext),s.push(this.lexer.yylloc),n.push(m[1]),f=null,p?(f=p,p=null):(a=this.lexer.yyleng,o=this.lexer.yytext,h=this.lexer.yylineno,c=this.lexer.yylloc,l>0&&l--);break;case 2:if(x=this.productions_[m[1]][1],$.$=r[r.length-x],$._$={first_line:s[s.length-(x||1)].first_line,last_line:s[s.length-1].last_line,first_column:s[s.length-(x||1)].first_column,last_column:s[s.length-1].last_column},u&&($._$.range=[s[s.length-(x||1)].range[0],s[s.length-1].range[1]]),void 0!==(b=this.performAction.call($,o,a,h,this.yy,m[1],r,s)))return b;x&&(n=n.slice(0,-1*x*2),r=r.slice(0,-1*x),s=s.slice(0,-1*x)),n.push(this.productions_[m[1]][0]),r.push($.$),s.push($._$),_=i[n[n.length-2]][n[n.length-1]],n.push(_);break;case 3:return!0}}return!0}},e=function(){var t={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t){return this._input=t,this._more=this._less=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e-1),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var s=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[s[0],s[0]+this.yyleng-e]),this},more:function(){return this._more=!0,this},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},next:function(){if(this.done)return this.EOF;var t,e,n,r,s;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),o=0;oe[0].length)||(e=n,r=o,this.options.flex));o++);return e?((s=e[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=s.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:s?s[s.length-1].length-s[s.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+e[0].length},this.yytext+=e[0],this.match+=e[0],this.matches=e,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._input=this._input.slice(e[0].length),this.matched+=e[0],t=this.performAction.call(this,this.yy,this,i[r],this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),t||void 0):""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){var t=this.next();return void 0!==t?t:this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.pop()},_currentRules:function(){return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules},topState:function(){return this.conditionStack[this.conditionStack.length-2]},pushState:function(t){this.begin(t)},options:{},performAction:function(t,e,n,r){switch(n){case 0:return"*";case 1:return"/";case 2:return"-";case 3:return"+";case 4:return"^";case 5:return"%";case 6:return"(";case 7:return")";case 8:return",";case 9:return"==";case 10:return"!=";case 11:return"~=";case 12:return">=";case 13:return"<=";case 14:return"<";case 15:return">";case 16:return"?";case 17:return":";case 18:return"and";case 19:return"or";case 20:return"not";case 21:return"in";case 22:return"of";case 23:break;case 24:return"NUMBER";case 25:return e.yytext=JSON.stringify(e.yytext),"SYMBOL";case 26:return e.yytext=t.buildString("'",e.yytext),"SYMBOL";case 27:return e.yytext=t.buildString('"',e.yytext),"STRING";case 28:return"EOF"}},rules:[/^(?:\*)/,/^(?:\/)/,/^(?:-)/,/^(?:\+)/,/^(?:\^)/,/^(?:\%)/,/^(?:\()/,/^(?:\))/,/^(?:\,)/,/^(?:==)/,/^(?:\!=)/,/^(?:\~=)/,/^(?:>=)/,/^(?:<=)/,/^(?:<)/,/^(?:>)/,/^(?:\?)/,/^(?:\:)/,/^(?:and[^\w])/,/^(?:or[^\w])/,/^(?:not[^\w])/,/^(?:in[^\w])/,/^(?:of[^\w])/,/^(?:\s+)/,/^(?:[0-9]+(?:\.[0-9]+)?\b)/,/^(?:[a-zA-Z$_][\.a-zA-Z0-9$_]*)/,/^(?:'(?:\\'|\\\\|[^'\\])*')/,/^(?:"(?:\\"|\\\\|[^"\\])*")/,/^(?:$)/],conditions:{INITIAL:{rules:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28],inclusive:!0}}};return t}();function n(){this.yy={}}return t.lexer=e,n.prototype=t,t.Parser=n,new n}();const n=e;e.Parser;const r={isfn:function(t,e){return t.hasOwnProperty(e)&&"function"==typeof t[e]},unknown:function(t){throw ReferenceError("Unknown function: "+t+"()")},coerceArray:function(t){return Array.isArray(t)?t:[t]},coerceBoolean:function(t){return"boolean"==typeof t?+t:t},isSubset:function(t,e){const n=r.coerceArray(t),s=r.coerceArray(e);return+n.every(t=>s.includes(t))},buildString:function(t,e){t=String(t)[0];let n="";if((e=String(e))[0]!==t||e[e.length-1]!==t)throw new Error("Unexpected internal error: String literal doesn't begin/end with the right quotation mark.");for(let r=1;r=e.length-1)throw new Error("Unexpected internal error: Unescaped backslash at the end of string literal.");if("\\"===e[r])n+="\\";else{if(e[r]!==t)throw new Error("Unexpected internal error: Invalid escaped character in string literal: "+e[r]);n+=t}}else{if(e[r]===t)throw new Error("Unexpected internal error: String literal contains unescaped quotation mark.");n+=e[r]}return JSON.stringify(n)}};return n.yy=Object.create(r),t.compileExpression=function(t,e){if(arguments.length>2)throw new TypeError("Too many arguments.");e="object"==typeof e?e:{};let{extraFunctions:s,customProp:i}=e;for(let t of Object.getOwnPropertyNames(e))if("extraFunctions"!==t&&"customProp"!==t)throw new TypeError("Unknown option: "+t);let o={abs:Math.abs,ceil:Math.ceil,floor:Math.floor,log:Math.log,max:Math.max,min:Math.min,random:Math.random,round:Math.round,sqrt:Math.sqrt};if(s)for(var h in s)s.hasOwnProperty(h)&&(o[h]=s[h]);let a=n.parse(t),l=[];function c(t){Array.isArray(t)?t.forEach(c):l.push(t)}function u(t,e){return Object.prototype.hasOwnProperty.call(e||{},t)?e[t]:void 0}function y(t){return function(e){return Object.prototype.hasOwnProperty.call(t||{},e)?t[e]:void 0}}l.push("return "),a.forEach(c),l.push(";"),"function"==typeof i&&(u=(t,e)=>r.coerceBoolean(i(t,y(e),e)));let f=new Function("fns","std","prop","data",l.join(""));return function(t){try{return f(o,r,u,t)}catch(t){return t}}},Object.defineProperty(t,"__esModule",{value:!0}),t}({}); \ No newline at end of file +var filtrex=function(t){"use strict";var e=function(){var t={trace:function(){},yy:{},symbols_:{error:2,expressions:3,e:4,EOF:5,"+":6,"-":7,"*":8,"/":9,"%":10,"^":11,and:12,or:13,not:14,"==":15,"!=":16,"~=":17,"<":18,"<=":19,">":20,">=":21,"?":22,":":23,"(":24,")":25,array:26,",":27,NUMBER:28,STRING:29,SYMBOL:30,of:31,argsList:32,in:33,inSet:34,$accept:0,$end:1},terminals_:{2:"error",5:"EOF",6:"+",7:"-",8:"*",9:"/",10:"%",11:"^",12:"and",13:"or",14:"not",15:"==",16:"!=",17:"~=",18:"<",19:"<=",20:">",21:">=",22:"?",23:":",24:"(",25:")",27:",",28:"NUMBER",29:"STRING",30:"SYMBOL",31:"of",33:"in"},productions_:[0,[3,2],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,2],[4,3],[4,3],[4,2],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,5],[4,3],[4,5],[4,1],[4,1],[4,1],[4,3],[4,3],[4,4],[4,3],[4,4],[32,1],[32,3],[34,1],[34,3],[26,1],[26,3]],performAction:function(t,e,n,r,i,s,o){var h=s.length-1;switch(i){case 1:return s[h-1];case 2:this.$=["(","",s[h-2]," + ",s[h],"",")"];break;case 3:this.$=["(","",s[h-2]," - ",s[h],"",")"];break;case 4:this.$=["(","",s[h-2]," * ",s[h],"",")"];break;case 5:this.$=["(","",s[h-2]," / ",s[h],"",")"];break;case 6:this.$=["(","",s[h-2]," % ",s[h],"",")"];break;case 7:this.$=["(","Math.pow( ",s[h-2],", ",s[h]," )",")"];break;case 8:this.$=["(","- ",s[h],"",")"];break;case 9:this.$=["(","","std.coerceBoolean","(",s[h-2],") && ","std.coerceBoolean","(",s[h],")",")"];break;case 10:this.$=["(","","std.coerceBoolean","(",s[h-2],") || ","std.coerceBoolean","(",s[h],")",")"];break;case 11:this.$=["(","! ","std.coerceBoolean","(",s[h],")",")"];break;case 12:this.$=["(","",s[h-2]," === ",s[h],"",")"];break;case 13:this.$=["(","",s[h-2]," !== ",s[h],"",")"];break;case 14:this.$=["(","RegExp(",s[h],").test(",s[h-2],")",")"];break;case 15:this.$=["(","",s[h-2]," < ",s[h],"",")"];break;case 16:this.$=["(","",s[h-2]," <= ",s[h],"",")"];break;case 17:this.$=["(","",s[h-2]," > ",s[h],"",")"];break;case 18:this.$=["(","",s[h-2]," >= ",s[h],"",")"];break;case 19:this.$=["(","",s[h-4]," ? ",s[h-2]," : ",s[h],"",")"];break;case 20:this.$=["(","",s[h-1],"",")"];break;case 21:this.$=["(","[ ",s[h-3],", ",s[h-1]," ]",")"];break;case 22:case 23:this.$=["(","",s[h],"",")"];break;case 24:this.$=["(","prop(",s[h],", data)",")"];break;case 25:this.$=["(","prop(",s[h-2],", ",s[h],")",")"];break;case 26:this.$=["(","std.isfn(fns, ",s[h-2],") ? fns[",s[h-2],"]() : std.unknown(",s[h-2],")",")"];break;case 27:this.$=["(","std.isfn(fns, ",s[h-3],") ? fns[",s[h-3],"](",s[h-1],") : std.unknown(",s[h-3],")",")"];break;case 28:this.$=["(","std.isSubset(",s[h-2],", ",s[h],")",")"];break;case 29:this.$=["(","!std.isSubset(",s[h-3],", ",s[h],")",")"];break;case 30:this.$=["",s[h],""];break;case 31:this.$=["",s[h-2],", ",s[h],""];break;case 32:this.$=["o === ",s[h],""];break;case 33:this.$=["",s[h-2]," || o === ",s[h],""];break;case 34:this.$=["",s[h],""];break;case 35:this.$=["",s[h-2],", ",s[h],""]}},table:[{3:1,4:2,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{1:[3]},{5:[1,9],6:[1,10],7:[1,11],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[1,16],13:[1,17],14:[1,27],15:[1,18],16:[1,19],17:[1,20],18:[1,21],19:[1,22],20:[1,23],21:[1,24],22:[1,25],33:[1,26]},{4:28,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:29,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:30,7:[1,3],14:[1,4],24:[1,5],26:31,28:[1,6],29:[1,7],30:[1,8]},{5:[2,22],6:[2,22],7:[2,22],8:[2,22],9:[2,22],10:[2,22],11:[2,22],12:[2,22],13:[2,22],14:[2,22],15:[2,22],16:[2,22],17:[2,22],18:[2,22],19:[2,22],20:[2,22],21:[2,22],22:[2,22],23:[2,22],25:[2,22],27:[2,22],33:[2,22]},{5:[2,23],6:[2,23],7:[2,23],8:[2,23],9:[2,23],10:[2,23],11:[2,23],12:[2,23],13:[2,23],14:[2,23],15:[2,23],16:[2,23],17:[2,23],18:[2,23],19:[2,23],20:[2,23],21:[2,23],22:[2,23],23:[2,23],25:[2,23],27:[2,23],33:[2,23]},{5:[2,24],6:[2,24],7:[2,24],8:[2,24],9:[2,24],10:[2,24],11:[2,24],12:[2,24],13:[2,24],14:[2,24],15:[2,24],16:[2,24],17:[2,24],18:[2,24],19:[2,24],20:[2,24],21:[2,24],22:[2,24],23:[2,24],24:[1,33],25:[2,24],27:[2,24],31:[1,32],33:[2,24]},{1:[2,1]},{4:34,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:35,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:36,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:37,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:38,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:39,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:40,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:41,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:42,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:43,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:44,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:45,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:46,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:47,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:48,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:49,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:50,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{33:[1,51]},{5:[2,8],6:[2,8],7:[2,8],8:[2,8],9:[2,8],10:[2,8],11:[2,8],12:[2,8],13:[2,8],14:[2,8],15:[2,8],16:[2,8],17:[2,8],18:[2,8],19:[2,8],20:[2,8],21:[2,8],22:[2,8],23:[2,8],25:[2,8],27:[2,8],33:[2,8]},{5:[2,11],6:[2,11],7:[2,11],8:[2,11],9:[2,11],10:[2,11],11:[2,11],12:[2,11],13:[2,11],14:[2,11],15:[2,11],16:[2,11],17:[2,11],18:[2,11],19:[2,11],20:[2,11],21:[2,11],22:[2,11],23:[2,11],25:[2,11],27:[2,11],33:[2,11]},{6:[1,10],7:[1,11],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[1,16],13:[1,17],14:[1,27],15:[1,18],16:[1,19],17:[1,20],18:[1,21],19:[1,22],20:[1,23],21:[1,24],22:[1,25],25:[1,52],27:[2,34],33:[1,26]},{27:[1,53]},{4:54,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{4:57,7:[1,3],14:[1,4],24:[1,5],25:[1,55],28:[1,6],29:[1,7],30:[1,8],32:56},{5:[2,2],6:[2,2],7:[2,2],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[2,2],13:[2,2],14:[1,27],15:[2,2],16:[2,2],17:[2,2],18:[2,2],19:[2,2],20:[2,2],21:[2,2],22:[2,2],23:[2,2],25:[2,2],27:[2,2],33:[2,2]},{5:[2,3],6:[2,3],7:[2,3],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[2,3],13:[2,3],14:[1,27],15:[2,3],16:[2,3],17:[2,3],18:[2,3],19:[2,3],20:[2,3],21:[2,3],22:[2,3],23:[2,3],25:[2,3],27:[2,3],33:[2,3]},{5:[2,4],6:[2,4],7:[2,4],8:[2,4],9:[2,4],10:[2,4],11:[1,15],12:[2,4],13:[2,4],14:[1,27],15:[2,4],16:[2,4],17:[2,4],18:[2,4],19:[2,4],20:[2,4],21:[2,4],22:[2,4],23:[2,4],25:[2,4],27:[2,4],33:[2,4]},{5:[2,5],6:[2,5],7:[2,5],8:[2,5],9:[2,5],10:[2,5],11:[1,15],12:[2,5],13:[2,5],14:[1,27],15:[2,5],16:[2,5],17:[2,5],18:[2,5],19:[2,5],20:[2,5],21:[2,5],22:[2,5],23:[2,5],25:[2,5],27:[2,5],33:[2,5]},{5:[2,6],6:[2,6],7:[2,6],8:[2,6],9:[2,6],10:[2,6],11:[1,15],12:[2,6],13:[2,6],14:[1,27],15:[2,6],16:[2,6],17:[2,6],18:[2,6],19:[2,6],20:[2,6],21:[2,6],22:[2,6],23:[2,6],25:[2,6],27:[2,6],33:[2,6]},{5:[2,7],6:[2,7],7:[2,7],8:[2,7],9:[2,7],10:[2,7],11:[2,7],12:[2,7],13:[2,7],14:[1,27],15:[2,7],16:[2,7],17:[2,7],18:[2,7],19:[2,7],20:[2,7],21:[2,7],22:[2,7],23:[2,7],25:[2,7],27:[2,7],33:[2,7]},{5:[2,9],6:[1,10],7:[1,11],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[2,9],13:[2,9],14:[1,27],15:[1,18],16:[1,19],17:[1,20],18:[1,21],19:[1,22],20:[1,23],21:[1,24],22:[2,9],23:[2,9],25:[2,9],27:[2,9],33:[1,26]},{5:[2,10],6:[1,10],7:[1,11],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[1,16],13:[2,10],14:[1,27],15:[1,18],16:[1,19],17:[1,20],18:[1,21],19:[1,22],20:[1,23],21:[1,24],22:[2,10],23:[2,10],25:[2,10],27:[2,10],33:[1,26]},{5:[2,12],6:[1,10],7:[1,11],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[2,12],13:[2,12],14:[1,27],15:[2,12],16:[2,12],17:[2,12],18:[1,21],19:[1,22],20:[1,23],21:[1,24],22:[2,12],23:[2,12],25:[2,12],27:[2,12],33:[2,12]},{5:[2,13],6:[1,10],7:[1,11],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[2,13],13:[2,13],14:[1,27],15:[2,13],16:[2,13],17:[2,13],18:[1,21],19:[1,22],20:[1,23],21:[1,24],22:[2,13],23:[2,13],25:[2,13],27:[2,13],33:[2,13]},{5:[2,14],6:[1,10],7:[1,11],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[2,14],13:[2,14],14:[1,27],15:[2,14],16:[2,14],17:[2,14],18:[1,21],19:[1,22],20:[1,23],21:[1,24],22:[2,14],23:[2,14],25:[2,14],27:[2,14],33:[2,14]},{5:[2,15],6:[1,10],7:[1,11],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[2,15],13:[2,15],14:[1,27],15:[2,15],16:[2,15],17:[2,15],18:[2,15],19:[2,15],20:[2,15],21:[2,15],22:[2,15],23:[2,15],25:[2,15],27:[2,15],33:[2,15]},{5:[2,16],6:[1,10],7:[1,11],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[2,16],13:[2,16],14:[1,27],15:[2,16],16:[2,16],17:[2,16],18:[2,16],19:[2,16],20:[2,16],21:[2,16],22:[2,16],23:[2,16],25:[2,16],27:[2,16],33:[2,16]},{5:[2,17],6:[1,10],7:[1,11],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[2,17],13:[2,17],14:[1,27],15:[2,17],16:[2,17],17:[2,17],18:[2,17],19:[2,17],20:[2,17],21:[2,17],22:[2,17],23:[2,17],25:[2,17],27:[2,17],33:[2,17]},{5:[2,18],6:[1,10],7:[1,11],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[2,18],13:[2,18],14:[1,27],15:[2,18],16:[2,18],17:[2,18],18:[2,18],19:[2,18],20:[2,18],21:[2,18],22:[2,18],23:[2,18],25:[2,18],27:[2,18],33:[2,18]},{6:[1,10],7:[1,11],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[1,16],13:[1,17],14:[1,27],15:[1,18],16:[1,19],17:[1,20],18:[1,21],19:[1,22],20:[1,23],21:[1,24],22:[1,25],23:[1,58],33:[1,26]},{5:[2,28],6:[1,10],7:[1,11],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[2,28],13:[2,28],14:[1,27],15:[1,18],16:[1,19],17:[1,20],18:[1,21],19:[1,22],20:[1,23],21:[1,24],22:[2,28],23:[2,28],25:[2,28],27:[2,28],33:[2,28]},{4:59,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{5:[2,20],6:[2,20],7:[2,20],8:[2,20],9:[2,20],10:[2,20],11:[2,20],12:[2,20],13:[2,20],14:[2,20],15:[2,20],16:[2,20],17:[2,20],18:[2,20],19:[2,20],20:[2,20],21:[2,20],22:[2,20],23:[2,20],25:[2,20],27:[2,20],33:[2,20]},{4:60,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{5:[2,25],6:[2,25],7:[2,25],8:[2,25],9:[2,25],10:[2,25],11:[2,25],12:[2,25],13:[2,25],14:[2,25],15:[2,25],16:[2,25],17:[2,25],18:[2,25],19:[2,25],20:[2,25],21:[2,25],22:[2,25],23:[2,25],25:[2,25],27:[2,25],33:[2,25]},{5:[2,26],6:[2,26],7:[2,26],8:[2,26],9:[2,26],10:[2,26],11:[2,26],12:[2,26],13:[2,26],14:[2,26],15:[2,26],16:[2,26],17:[2,26],18:[2,26],19:[2,26],20:[2,26],21:[2,26],22:[2,26],23:[2,26],25:[2,26],27:[2,26],33:[2,26]},{25:[1,61],27:[1,62]},{6:[1,10],7:[1,11],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[1,16],13:[1,17],14:[1,27],15:[1,18],16:[1,19],17:[1,20],18:[1,21],19:[1,22],20:[1,23],21:[1,24],22:[1,25],25:[2,30],27:[2,30],33:[1,26]},{4:63,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{5:[2,29],6:[2,29],7:[2,29],8:[2,29],9:[2,29],10:[2,29],11:[2,29],12:[2,29],13:[2,29],14:[2,29],15:[2,29],16:[2,29],17:[2,29],18:[2,29],19:[2,29],20:[2,29],21:[2,29],22:[2,29],23:[2,29],25:[2,29],27:[2,29],33:[2,29]},{6:[1,10],7:[1,11],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[1,16],13:[1,17],14:[1,27],15:[1,18],16:[1,19],17:[1,20],18:[1,21],19:[1,22],20:[1,23],21:[1,24],22:[1,25],25:[1,64],27:[2,35],33:[1,26]},{5:[2,27],6:[2,27],7:[2,27],8:[2,27],9:[2,27],10:[2,27],11:[2,27],12:[2,27],13:[2,27],14:[2,27],15:[2,27],16:[2,27],17:[2,27],18:[2,27],19:[2,27],20:[2,27],21:[2,27],22:[2,27],23:[2,27],25:[2,27],27:[2,27],33:[2,27]},{4:65,7:[1,3],14:[1,4],24:[1,5],28:[1,6],29:[1,7],30:[1,8]},{5:[2,19],6:[1,10],7:[1,11],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[1,16],13:[1,17],14:[1,27],15:[1,18],16:[1,19],17:[1,20],18:[1,21],19:[1,22],20:[1,23],21:[1,24],22:[2,19],23:[2,19],25:[2,19],27:[2,19],33:[1,26]},{5:[2,21],6:[2,21],7:[2,21],8:[2,21],9:[2,21],10:[2,21],11:[2,21],12:[2,21],13:[2,21],14:[2,21],15:[2,21],16:[2,21],17:[2,21],18:[2,21],19:[2,21],20:[2,21],21:[2,21],22:[2,21],23:[2,21],25:[2,21],27:[2,21],33:[2,21]},{6:[1,10],7:[1,11],8:[1,12],9:[1,13],10:[1,14],11:[1,15],12:[1,16],13:[1,17],14:[1,27],15:[1,18],16:[1,19],17:[1,20],18:[1,21],19:[1,22],20:[1,23],21:[1,24],22:[1,25],25:[2,31],27:[2,31],33:[1,26]}],defaultActions:{9:[2,1]},parseError:function(t,e){throw new Error(t)},parse:function(t){var e=this,n=[0],r=[null],i=[],s=this.table,o="",h=0,a=0,l=0;this.lexer.setInput(t),this.lexer.yy=this.yy,this.yy.lexer=this.lexer,this.yy.parser=this,void 0===this.lexer.yylloc&&(this.lexer.yylloc={});var c=this.lexer.yylloc;i.push(c);var u=this.lexer.options&&this.lexer.options.ranges;function y(){var t;return"number"!=typeof(t=e.lexer.lex()||1)&&(t=e.symbols_[t]||t),t}"function"==typeof this.yy.parseError&&(this.parseError=this.yy.parseError);for(var f,p,g,d,m,b,x,_,w,k,$={};;){if(g=n[n.length-1],this.defaultActions[g]?d=this.defaultActions[g]:(null==f&&(f=y()),d=s[g]&&s[g][f]),void 0===d||!d.length||!d[0]){var E="";if(!l){for(b in w=[],s[g])this.terminals_[b]&&b>2&&w.push("'"+this.terminals_[b]+"'");E=this.lexer.showPosition?"Parse error on line "+(h+1)+":\n"+this.lexer.showPosition()+"\nExpecting "+w.join(", ")+", got '"+(this.terminals_[f]||f)+"'":"Parse error on line "+(h+1)+": Unexpected "+(1==f?"end of input":"'"+(this.terminals_[f]||f)+"'"),this.parseError(E,{text:this.lexer.match,token:this.terminals_[f]||f,line:this.lexer.yylineno,loc:c,expected:w})}if(3==l){if(1==f)throw new Error(E||"Parsing halted.");a=this.lexer.yyleng,o=this.lexer.yytext,h=this.lexer.yylineno,c=this.lexer.yylloc,f=y()}for(;!(2..toString()in s[g]);){if(0===g)throw new Error(E||"Parsing halted.");k=1,n.length=n.length-2*k,r.length=r.length-k,i.length=i.length-k,g=n[n.length-1]}p=2==f?null:f,f=2,d=s[g=n[n.length-1]]&&s[g][2],l=3}if(d[0]instanceof Array&&d.length>1)throw new Error("Parse Error: multiple actions possible at state: "+g+", token: "+f);switch(d[0]){case 1:n.push(f),r.push(this.lexer.yytext),i.push(this.lexer.yylloc),n.push(d[1]),f=null,p?(f=p,p=null):(a=this.lexer.yyleng,o=this.lexer.yytext,h=this.lexer.yylineno,c=this.lexer.yylloc,l>0&&l--);break;case 2:if(x=this.productions_[d[1]][1],$.$=r[r.length-x],$._$={first_line:i[i.length-(x||1)].first_line,last_line:i[i.length-1].last_line,first_column:i[i.length-(x||1)].first_column,last_column:i[i.length-1].last_column},u&&($._$.range=[i[i.length-(x||1)].range[0],i[i.length-1].range[1]]),void 0!==(m=this.performAction.call($,o,a,h,this.yy,d[1],r,i)))return m;x&&(n=n.slice(0,-1*x*2),r=r.slice(0,-1*x),i=i.slice(0,-1*x)),n.push(this.productions_[d[1]][0]),r.push($.$),i.push($._$),_=s[n[n.length-2]][n[n.length-1]],n.push(_);break;case 3:return!0}}return!0}},e=function(){var t={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t){return this._input=t,this._more=this._less=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e-1),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this},more:function(){return this._more=!0,this},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},next:function(){if(this.done)return this.EOF;var t,e,n,r,i;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var s=this._currentRules(),o=0;oe[0].length)||(e=n,r=o,this.options.flex));o++);return e?((i=e[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=i.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:i?i[i.length-1].length-i[i.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+e[0].length},this.yytext+=e[0],this.match+=e[0],this.matches=e,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._input=this._input.slice(e[0].length),this.matched+=e[0],t=this.performAction.call(this,this.yy,this,s[r],this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),t||void 0):""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){var t=this.next();return void 0!==t?t:this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.pop()},_currentRules:function(){return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules},topState:function(){return this.conditionStack[this.conditionStack.length-2]},pushState:function(t){this.begin(t)},options:{},performAction:function(t,e,n,r){switch(n){case 0:return"*";case 1:return"/";case 2:return"-";case 3:return"+";case 4:return"^";case 5:return"%";case 6:return"(";case 7:return")";case 8:return",";case 9:return"==";case 10:return"!=";case 11:return"~=";case 12:return">=";case 13:return"<=";case 14:return"<";case 15:return">";case 16:return"?";case 17:return":";case 18:return"and";case 19:return"or";case 20:return"not";case 21:return"in";case 22:return"of";case 23:break;case 24:return"NUMBER";case 25:return e.yytext=JSON.stringify(e.yytext),"SYMBOL";case 26:return e.yytext=t.buildString("'",e.yytext),"SYMBOL";case 27:return e.yytext=t.buildString('"',e.yytext),"STRING";case 28:return"EOF"}},rules:[/^(?:\*)/,/^(?:\/)/,/^(?:-)/,/^(?:\+)/,/^(?:\^)/,/^(?:\%)/,/^(?:\()/,/^(?:\))/,/^(?:\,)/,/^(?:==)/,/^(?:\!=)/,/^(?:\~=)/,/^(?:>=)/,/^(?:<=)/,/^(?:<)/,/^(?:>)/,/^(?:\?)/,/^(?:\:)/,/^(?:and[^\w])/,/^(?:or[^\w])/,/^(?:not[^\w])/,/^(?:in[^\w])/,/^(?:of[^\w])/,/^(?:\s+)/,/^(?:[0-9]+(?:\.[0-9]+)?\b)/,/^(?:[a-zA-Z$_][\.a-zA-Z0-9$_]*)/,/^(?:'(?:\\'|\\\\|[^'\\])*')/,/^(?:"(?:\\"|\\\\|[^"\\])*")/,/^(?:$)/],conditions:{INITIAL:{rules:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28],inclusive:!0}}};return t}();function n(){this.yy={}}return t.lexer=e,n.prototype=t,t.Parser=n,new n}();const n=e;function r(t,e){return("object"==typeof t||"function"==typeof t)&&Object.prototype.hasOwnProperty.call(t,e)}e.Parser;const i="function"!=typeof Symbol||"symbol"!=typeof Symbol.toPrimitive?()=>{}:t=>{if("function"==typeof t[Symbol.toPrimitive])return t[Symbol.toPrimitive]};const s={isfn:function(t,e){return r(t,e)&&"function"==typeof t[e]},unknown:function(t){throw new ReferenceError("Unknown function: "+t+"()")},coerceArray:function(t){if(null==t)throw new TypeError(`Expected a list, but got ${t} instead.`);return Array.isArray(t)?t:[t]},coerceNumber:function(t){const e=t;if(null==t)throw new TypeError(`Expected a numeric value, but got ${t} instead.`);if(Array.isArray(t)&&1===t.length&&(t=t[0]),"object"==typeof t&&(t=function(t,e){if("object"==typeof t&&"function"==typeof t)try{let n=i(t)(e);if(typeof n===e)return n;if(n=t.valueOf(),typeof n===e)return n}finally{return}}(t)),"number"==typeof t||"bigint"==typeof t)return t;throw new TypeError(`Expected a numeric value, but got an ${typeof e} instead.`)},coerceBoolean:function(t){if("boolean"==typeof t)return t;if("object"==typeof t&&t instanceof Boolean)return t.valueOf();throw new TypeError(`Expected a boolean (“true” or “false”) value, but got an ${typeof t} instead.`)},isSubset:function(t,e){const n=s.coerceArray(t),r=s.coerceArray(e);return n.every(t=>r.includes(t))},buildString:function(t,e){t=String(t)[0];let n="";if((e=String(e))[0]!==t||e[e.length-1]!==t)throw new Error("Unexpected internal error: String literal doesn't begin/end with the right quotation mark.");for(let r=1;r=e.length-1)throw new Error("Unexpected internal error: Unescaped backslash at the end of string literal.");if("\\"===e[r])n+="\\";else{if(e[r]!==t)throw new Error("Unexpected internal error: Invalid escaped character in string literal: "+e[r]);n+=t}}else{if(e[r]===t)throw new Error("Unexpected internal error: String literal contains unescaped quotation mark.");n+=e[r]}return JSON.stringify(n)}};return n.yy=Object.create(s),t.compileExpression=function(t,e){if(arguments.length>2)throw new TypeError("Too many arguments.");e="object"==typeof e?e:{};let{extraFunctions:i,customProp:o}=e;for(let t of Object.getOwnPropertyNames(e))if("extraFunctions"!==t&&"customProp"!==t)throw new TypeError("Unknown option: "+t);let h={abs:Math.abs,ceil:Math.ceil,floor:Math.floor,log:Math.log,max:Math.max,min:Math.min,random:Math.random,round:Math.round,sqrt:Math.sqrt,exists:t=>null!=t,empty:t=>null==t||""===t||Array.isArray(t)&&0===t.length};if(i)for(var a in i)r(i,a)&&(h[a]=i[a]);let l=n.parse(t),c=[];function u(t){Array.isArray(t)?t.forEach(u):c.push(t)}function y(t,e){return r(e||{},t)?e[t]:void 0}function f(t){return function(e){return r(t||{},e)?t[e]:void 0}}c.push("return "),l.forEach(u),c.push(";"),"function"==typeof o&&(y=(t,e)=>o(t,f(e),e));let p=new Function("fns","std","prop","data",c.join(""));return function(t){try{return p(h,s,y,t)}catch(t){return t}}},Object.defineProperty(t,"__esModule",{value:!0}),t}({}); \ No newline at end of file diff --git a/dist/cjs/filtrex.js b/dist/cjs/filtrex.js index afb0b93..1d57fc2 100644 --- a/dist/cjs/filtrex.js +++ b/dist/cjs/filtrex.js @@ -117,106 +117,106 @@ var _parser = (function() { case 1: return $$[$0 - 1]; case 2: - this.$ = ["(", $$[$0 - 2], "+", $$[$0], ")"]; + this.$ = ["(", "", $$[$0 - 2], " + ", $$[$0], "", ")"]; break; case 3: - this.$ = ["(", $$[$0 - 2], "-", $$[$0], ")"]; + this.$ = ["(", "", $$[$0 - 2], " - ", $$[$0], "", ")"]; break; case 4: - this.$ = ["(", $$[$0 - 2], "*", $$[$0], ")"]; + this.$ = ["(", "", $$[$0 - 2], " * ", $$[$0], "", ")"]; break; case 5: - this.$ = ["(", $$[$0 - 2], "/", $$[$0], ")"]; + this.$ = ["(", "", $$[$0 - 2], " / ", $$[$0], "", ")"]; break; case 6: - this.$ = ["(", $$[$0 - 2], "%", $$[$0], ")"]; + this.$ = ["(", "", $$[$0 - 2], " % ", $$[$0], "", ")"]; break; case 7: - this.$ = ["(", "Math.pow(", $$[$0 - 2], ",", $$[$0], ")", ")"]; + this.$ = ["(", "Math.pow( ", $$[$0 - 2], ", ", $$[$0], " )", ")"]; break; case 8: - this.$ = ["(", "-", $$[$0], ")"]; + this.$ = ["(", "- ", $$[$0], "", ")"]; break; case 9: - this.$ = ["(", "Number(", $$[$0 - 2], "&&", $$[$0], ")", ")"]; + this.$ = ["(", "", "std.coerceBoolean", "(", $$[$0 - 2], ") && ", "std.coerceBoolean", "(", $$[$0], ")", ")"]; break; case 10: - this.$ = ["(", "Number(", $$[$0 - 2], "||", $$[$0], ")", ")"]; + this.$ = ["(", "", "std.coerceBoolean", "(", $$[$0 - 2], ") || ", "std.coerceBoolean", "(", $$[$0], ")", ")"]; break; case 11: - this.$ = ["(", "Number(!", $$[$0], ")", ")"]; + this.$ = ["(", "! ", "std.coerceBoolean", "(", $$[$0], ")", ")"]; break; case 12: - this.$ = ["(", "Number(", $$[$0 - 2], "==", $$[$0], ")", ")"]; + this.$ = ["(", "", $$[$0 - 2], " === ", $$[$0], "", ")"]; break; case 13: - this.$ = ["(", "Number(", $$[$0 - 2], "!=", $$[$0], ")", ")"]; + this.$ = ["(", "", $$[$0 - 2], " !== ", $$[$0], "", ")"]; break; case 14: - this.$ = ["(", "Number(RegExp(", $$[$0], ").test(", $$[$0 - 2], "))", ")"]; + this.$ = ["(", "RegExp(", $$[$0], ").test(", $$[$0 - 2], ")", ")"]; break; case 15: - this.$ = ["(", "Number(", $$[$0 - 2], "<", $$[$0], ")", ")"]; + this.$ = ["(", "", $$[$0 - 2], " < ", $$[$0], "", ")"]; break; case 16: - this.$ = ["(", "Number(", $$[$0 - 2], "<=", $$[$0], ")", ")"]; + this.$ = ["(", "", $$[$0 - 2], " <= ", $$[$0], "", ")"]; break; case 17: - this.$ = ["(", "Number(", $$[$0 - 2], "> ", $$[$0], ")", ")"]; + this.$ = ["(", "", $$[$0 - 2], " > ", $$[$0], "", ")"]; break; case 18: - this.$ = ["(", "Number(", $$[$0 - 2], ">=", $$[$0], ")", ")"]; + this.$ = ["(", "", $$[$0 - 2], " >= ", $$[$0], "", ")"]; break; case 19: - this.$ = ["(", $$[$0 - 4], "?", $$[$0 - 2], ":", $$[$0], ")"]; + this.$ = ["(", "", $$[$0 - 4], " ? ", $$[$0 - 2], " : ", $$[$0], "", ")"]; break; case 20: - this.$ = ["(", $$[$0 - 1], ")"]; + this.$ = ["(", "", $$[$0 - 1], "", ")"]; break; case 21: - this.$ = ["(", "[", $$[$0 - 3], ",", $$[$0 - 1], "]", ")"]; + this.$ = ["(", "[ ", $$[$0 - 3], ", ", $$[$0 - 1], " ]", ")"]; break; case 22: - this.$ = ["(", $$[$0], ")"]; + this.$ = ["(", "", $$[$0], "", ")"]; break; case 23: - this.$ = ["(", $$[$0], ")"]; + this.$ = ["(", "", $$[$0], "", ")"]; break; case 24: this.$ = ["(", "prop(", $$[$0], ", data)", ")"]; break; case 25: - this.$ = ["(", "prop(", $$[$0 - 2], ",", $$[$0], ")", ")"]; + this.$ = ["(", "prop(", $$[$0 - 2], ", ", $$[$0], ")", ")"]; break; case 26: - this.$ = ["(", "(std.isfn(fns, ", $$[$0 - 2], ") ? fns[", $$[$0 - 2], "]() : std.unknown(", $$[$0 - 2], "))", ")"]; + this.$ = ["(", "std.isfn(fns, ", $$[$0 - 2], ") ? fns[", $$[$0 - 2], "]() : std.unknown(", $$[$0 - 2], ")", ")"]; break; case 27: - this.$ = ["(", "(std.isfn(fns, ", $$[$0 - 3], ") ? fns[", $$[$0 - 3], "](", $$[$0 - 1], ") : std.unknown(", $$[$0 - 3], "))", ")"]; + this.$ = ["(", "std.isfn(fns, ", $$[$0 - 3], ") ? fns[", $$[$0 - 3], "](", $$[$0 - 1], ") : std.unknown(", $$[$0 - 3], ")", ")"]; break; case 28: this.$ = ["(", "std.isSubset(", $$[$0 - 2], ", ", $$[$0], ")", ")"]; break; case 29: - this.$ = ["(", "+!std.isSubset(", $$[$0 - 3], ", ", $$[$0], ")", ")"]; + this.$ = ["(", "!std.isSubset(", $$[$0 - 3], ", ", $$[$0], ")", ")"]; break; case 30: - this.$ = [$$[$0]]; + this.$ = ["", $$[$0], ""]; break; case 31: - this.$ = [$$[$0 - 2], ",", $$[$0]]; + this.$ = ["", $$[$0 - 2], ", ", $$[$0], ""]; break; case 32: - this.$ = ["o ==", $$[$0]]; + this.$ = ["o === ", $$[$0], ""]; break; case 33: - this.$ = [$$[$0 - 2], "|| o ==", $$[$0]]; + this.$ = ["", $$[$0 - 2], " || o === ", $$[$0], ""]; break; case 34: - this.$ = ["(", $$[$0], ")"]; + this.$ = ["", $$[$0], ""]; break; case 35: - this.$ = [$$[$0 - 2], ",", $$[$0]]; + this.$ = ["", $$[$0 - 2], ", ", $$[$0], ""]; break; } }, @@ -1691,6 +1691,56 @@ var _parser = (function() { const parser = _parser; _parser.Parser; +/** + * Determines whether an object has a property with the specified name. + * @param {object} obj the object to be checked + * @param {string|number} prop property name + */ +function hasOwnProperty(obj, prop) { + if (typeof obj === "object" || typeof obj === "function") { + return Object.prototype.hasOwnProperty.call(obj, prop) + } + + return false +} + +/** + * Safe getter for `v[Symbol.toPrimitive]`. + */ +const _toPrimitive = + typeof Symbol !== "function" || typeof Symbol.toPrimitive !== "symbol" + ? () => undefined + : (v) => { + if (typeof v[Symbol.toPrimitive] === "function") { + return v[Symbol.toPrimitive] + } + + return undefined + }; + +/** + * Attempt to convert an object to the required primitive type. + * @param {object} obj + * @param {"string"|"number"|"bigint"} type + * @returns {string|number|bigint|undefined} + */ +function toPrimitive(obj, type) { + if (typeof obj !== "object" || typeof obj !== "function") { + return undefined + } + + try { + let val = _toPrimitive(obj)(type); + if (typeof val === type) return val + + val = obj.valueOf(); + if (typeof val === type) return val + + } finally { + return undefined + } +} + // the parser is dynamically generated from generateParser.js at compile time // Shared utility functions @@ -1698,31 +1748,57 @@ const std = { isfn: function(fns, funcName) { - return fns.hasOwnProperty(funcName) && typeof fns[funcName] === "function"; + return hasOwnProperty(fns, funcName) && typeof fns[funcName] === "function"; }, unknown: function(funcName) { - throw ReferenceError('Unknown function: ' + funcName + '()'); + throw new ReferenceError('Unknown function: ' + funcName + '()'); }, coerceArray: function(value) { - if (Array.isArray(value)) + if (value === undefined || value === null) { + throw new TypeError(`Expected a list, but got ${value} instead.`) + } + + if (Array.isArray(value)) { return value; - else + } else { return [value]; + } + }, + + coerceNumber: function (value) { + const origValue = value; + + if (value === undefined || value === null) + throw new TypeError(`Expected a numeric value, but got ${value} instead.`) + + if (Array.isArray(value) && value.length === 1) + value = value[0]; + + if (typeof value === 'object') + value = toPrimitive(value); + + if (typeof value === 'number' || typeof value === 'bigint') + return value; + + throw new TypeError(`Expected a numeric value, but got an ${typeof origValue} instead.`) }, coerceBoolean: function(value) { if (typeof value === 'boolean') - return +value; - else - return value; + return value + + if (typeof value === 'object' && value instanceof Boolean) + return value.valueOf(); + + throw new TypeError(`Expected a boolean (“true” or “false”) value, but got an ${typeof value} instead.`) }, isSubset: function(a, b) { const A = std.coerceArray(a); const B = std.coerceArray(b); - return +A.every( val => B.includes(val) ); + return A.every( val => B.includes(val) ); }, buildString: function(quote, literal) @@ -1798,11 +1874,13 @@ function compileExpression(expression, options) { random: Math.random, round: Math.round, sqrt: Math.sqrt, + exists: (v) => v !== undefined && v !== null, + empty: (v) => v === undefined || v === null || v === '' || Array.isArray(v) && v.length === 0 }; if (extraFunctions) { for (var name in extraFunctions) { - if (extraFunctions.hasOwnProperty(name)) { + if (hasOwnProperty(extraFunctions, name)) { functions[name] = extraFunctions[name]; } } @@ -1831,17 +1909,17 @@ function compileExpression(expression, options) { // Metaprogramming functions function prop(name, obj) { - return Object.prototype.hasOwnProperty.call(obj||{}, name) ? obj[name] : undefined; + return hasOwnProperty(obj||{}, name) ? obj[name] : undefined; } function safeGetter(obj) { return function get(name) { - return Object.prototype.hasOwnProperty.call(obj||{}, name) ? obj[name] : undefined; + return hasOwnProperty(obj||{}, name) ? obj[name] : undefined; } } if (typeof customProp === 'function') { - prop = (name, obj) => std.coerceBoolean(customProp(name, safeGetter(obj), obj)); + prop = (name, obj) => customProp(name, safeGetter(obj), obj); } diff --git a/dist/esm/filtrex.mjs b/dist/esm/filtrex.mjs index a8687a9..30323cd 100644 --- a/dist/esm/filtrex.mjs +++ b/dist/esm/filtrex.mjs @@ -1,36 +1,63 @@ // the parser is dynamically generated from generateParser.js at compile time -import { parser } from './parser.mjs'; +import { parser } from './parser.mjs' +import { hasOwnProperty, toPrimitive } from './utils.mjs' // Shared utility functions const std = { isfn: function(fns, funcName) { - return fns.hasOwnProperty(funcName) && typeof fns[funcName] === "function"; + return hasOwnProperty(fns, funcName) && typeof fns[funcName] === "function"; }, unknown: function(funcName) { - throw ReferenceError('Unknown function: ' + funcName + '()'); + throw new ReferenceError('Unknown function: ' + funcName + '()'); }, coerceArray: function(value) { - if (Array.isArray(value)) + if (value === undefined || value === null) { + throw new TypeError(`Expected a list, but got ${value} instead.`) + } + + if (Array.isArray(value)) { return value; - else + } else { return [value]; + } + }, + + coerceNumber: function (value) { + const origValue = value + + if (value === undefined || value === null) + throw new TypeError(`Expected a numeric value, but got ${value} instead.`) + + if (Array.isArray(value) && value.length === 1) + value = value[0] + + if (typeof value === 'object') + value = toPrimitive(value) + + if (typeof value === 'number' || typeof value === 'bigint') + return value; + + throw new TypeError(`Expected a numeric value, but got an ${typeof origValue} instead.`) }, coerceBoolean: function(value) { if (typeof value === 'boolean') - return +value; - else - return value; + return value + + if (typeof value === 'object' && value instanceof Boolean) + return value.valueOf(); + + throw new TypeError(`Expected a boolean (“true” or “false”) value, but got an ${typeof value} instead.`) }, isSubset: function(a, b) { const A = std.coerceArray(a); const B = std.coerceArray(b); - return +A.every( val => B.includes(val) ); + return A.every( val => B.includes(val) ); }, buildString: function(quote, literal) @@ -106,11 +133,13 @@ export function compileExpression(expression, options) { random: Math.random, round: Math.round, sqrt: Math.sqrt, + exists: (v) => v !== undefined && v !== null, + empty: (v) => v === undefined || v === null || v === '' || Array.isArray(v) && v.length === 0 }; if (extraFunctions) { for (var name in extraFunctions) { - if (extraFunctions.hasOwnProperty(name)) { + if (hasOwnProperty(extraFunctions, name)) { functions[name] = extraFunctions[name]; } } @@ -139,17 +168,17 @@ export function compileExpression(expression, options) { // Metaprogramming functions function prop(name, obj) { - return Object.prototype.hasOwnProperty.call(obj||{}, name) ? obj[name] : undefined; + return hasOwnProperty(obj||{}, name) ? obj[name] : undefined; } function safeGetter(obj) { return function get(name) { - return Object.prototype.hasOwnProperty.call(obj||{}, name) ? obj[name] : undefined; + return hasOwnProperty(obj||{}, name) ? obj[name] : undefined; } } if (typeof customProp === 'function') { - prop = (name, obj) => std.coerceBoolean(customProp(name, safeGetter(obj), obj)); + prop = (name, obj) => customProp(name, safeGetter(obj), obj); } diff --git a/dist/esm/parser.mjs b/dist/esm/parser.mjs index 1d9fe98..0e7f183 100644 --- a/dist/esm/parser.mjs +++ b/dist/esm/parser.mjs @@ -114,106 +114,106 @@ var _parser = (function() { return $$[$0 - 1]; break; case 2: - this.$ = ["(", $$[$0 - 2], "+", $$[$0], ")"]; + this.$ = ["(", "", $$[$0 - 2], " + ", $$[$0], "", ")"]; break; case 3: - this.$ = ["(", $$[$0 - 2], "-", $$[$0], ")"]; + this.$ = ["(", "", $$[$0 - 2], " - ", $$[$0], "", ")"]; break; case 4: - this.$ = ["(", $$[$0 - 2], "*", $$[$0], ")"]; + this.$ = ["(", "", $$[$0 - 2], " * ", $$[$0], "", ")"]; break; case 5: - this.$ = ["(", $$[$0 - 2], "/", $$[$0], ")"]; + this.$ = ["(", "", $$[$0 - 2], " / ", $$[$0], "", ")"]; break; case 6: - this.$ = ["(", $$[$0 - 2], "%", $$[$0], ")"]; + this.$ = ["(", "", $$[$0 - 2], " % ", $$[$0], "", ")"]; break; case 7: - this.$ = ["(", "Math.pow(", $$[$0 - 2], ",", $$[$0], ")", ")"]; + this.$ = ["(", "Math.pow( ", $$[$0 - 2], ", ", $$[$0], " )", ")"]; break; case 8: - this.$ = ["(", "-", $$[$0], ")"]; + this.$ = ["(", "- ", $$[$0], "", ")"]; break; case 9: - this.$ = ["(", "Number(", $$[$0 - 2], "&&", $$[$0], ")", ")"]; + this.$ = ["(", "", "std.coerceBoolean", "(", $$[$0 - 2], ") && ", "std.coerceBoolean", "(", $$[$0], ")", ")"]; break; case 10: - this.$ = ["(", "Number(", $$[$0 - 2], "||", $$[$0], ")", ")"]; + this.$ = ["(", "", "std.coerceBoolean", "(", $$[$0 - 2], ") || ", "std.coerceBoolean", "(", $$[$0], ")", ")"]; break; case 11: - this.$ = ["(", "Number(!", $$[$0], ")", ")"]; + this.$ = ["(", "! ", "std.coerceBoolean", "(", $$[$0], ")", ")"]; break; case 12: - this.$ = ["(", "Number(", $$[$0 - 2], "==", $$[$0], ")", ")"]; + this.$ = ["(", "", $$[$0 - 2], " === ", $$[$0], "", ")"]; break; case 13: - this.$ = ["(", "Number(", $$[$0 - 2], "!=", $$[$0], ")", ")"]; + this.$ = ["(", "", $$[$0 - 2], " !== ", $$[$0], "", ")"]; break; case 14: - this.$ = ["(", "Number(RegExp(", $$[$0], ").test(", $$[$0 - 2], "))", ")"]; + this.$ = ["(", "RegExp(", $$[$0], ").test(", $$[$0 - 2], ")", ")"]; break; case 15: - this.$ = ["(", "Number(", $$[$0 - 2], "<", $$[$0], ")", ")"]; + this.$ = ["(", "", $$[$0 - 2], " < ", $$[$0], "", ")"]; break; case 16: - this.$ = ["(", "Number(", $$[$0 - 2], "<=", $$[$0], ")", ")"]; + this.$ = ["(", "", $$[$0 - 2], " <= ", $$[$0], "", ")"]; break; case 17: - this.$ = ["(", "Number(", $$[$0 - 2], "> ", $$[$0], ")", ")"]; + this.$ = ["(", "", $$[$0 - 2], " > ", $$[$0], "", ")"]; break; case 18: - this.$ = ["(", "Number(", $$[$0 - 2], ">=", $$[$0], ")", ")"]; + this.$ = ["(", "", $$[$0 - 2], " >= ", $$[$0], "", ")"]; break; case 19: - this.$ = ["(", $$[$0 - 4], "?", $$[$0 - 2], ":", $$[$0], ")"]; + this.$ = ["(", "", $$[$0 - 4], " ? ", $$[$0 - 2], " : ", $$[$0], "", ")"]; break; case 20: - this.$ = ["(", $$[$0 - 1], ")"]; + this.$ = ["(", "", $$[$0 - 1], "", ")"]; break; case 21: - this.$ = ["(", "[", $$[$0 - 3], ",", $$[$0 - 1], "]", ")"]; + this.$ = ["(", "[ ", $$[$0 - 3], ", ", $$[$0 - 1], " ]", ")"]; break; case 22: - this.$ = ["(", $$[$0], ")"]; + this.$ = ["(", "", $$[$0], "", ")"]; break; case 23: - this.$ = ["(", $$[$0], ")"]; + this.$ = ["(", "", $$[$0], "", ")"]; break; case 24: this.$ = ["(", "prop(", $$[$0], ", data)", ")"]; break; case 25: - this.$ = ["(", "prop(", $$[$0 - 2], ",", $$[$0], ")", ")"]; + this.$ = ["(", "prop(", $$[$0 - 2], ", ", $$[$0], ")", ")"]; break; case 26: - this.$ = ["(", "(std.isfn(fns, ", $$[$0 - 2], ") ? fns[", $$[$0 - 2], "]() : std.unknown(", $$[$0 - 2], "))", ")"]; + this.$ = ["(", "std.isfn(fns, ", $$[$0 - 2], ") ? fns[", $$[$0 - 2], "]() : std.unknown(", $$[$0 - 2], ")", ")"]; break; case 27: - this.$ = ["(", "(std.isfn(fns, ", $$[$0 - 3], ") ? fns[", $$[$0 - 3], "](", $$[$0 - 1], ") : std.unknown(", $$[$0 - 3], "))", ")"]; + this.$ = ["(", "std.isfn(fns, ", $$[$0 - 3], ") ? fns[", $$[$0 - 3], "](", $$[$0 - 1], ") : std.unknown(", $$[$0 - 3], ")", ")"]; break; case 28: this.$ = ["(", "std.isSubset(", $$[$0 - 2], ", ", $$[$0], ")", ")"]; break; case 29: - this.$ = ["(", "+!std.isSubset(", $$[$0 - 3], ", ", $$[$0], ")", ")"]; + this.$ = ["(", "!std.isSubset(", $$[$0 - 3], ", ", $$[$0], ")", ")"]; break; case 30: - this.$ = [$$[$0]]; + this.$ = ["", $$[$0], ""]; break; case 31: - this.$ = [$$[$0 - 2], ",", $$[$0]]; + this.$ = ["", $$[$0 - 2], ", ", $$[$0], ""]; break; case 32: - this.$ = ["o ==", $$[$0]]; + this.$ = ["o === ", $$[$0], ""]; break; case 33: - this.$ = [$$[$0 - 2], "|| o ==", $$[$0]]; + this.$ = ["", $$[$0 - 2], " || o === ", $$[$0], ""]; break; case 34: - this.$ = ["(", $$[$0], ")"]; + this.$ = ["", $$[$0], ""]; break; case 35: - this.$ = [$$[$0 - 2], ",", $$[$0]]; + this.$ = ["", $$[$0 - 2], ", ", $$[$0], ""]; break; } }, diff --git a/dist/esm/utils.mjs b/dist/esm/utils.mjs new file mode 100644 index 0000000..db17884 --- /dev/null +++ b/dist/esm/utils.mjs @@ -0,0 +1,50 @@ +/** + * Determines whether an object has a property with the specified name. + * @param {object} obj the object to be checked + * @param {string|number} prop property name + */ +export function hasOwnProperty(obj, prop) { + if (typeof obj === "object" || typeof obj === "function") { + return Object.prototype.hasOwnProperty.call(obj, prop) + } + + return false +} + +/** + * Safe getter for `v[Symbol.toPrimitive]`. + */ +const _toPrimitive = + typeof Symbol !== "function" || typeof Symbol.toPrimitive !== "symbol" + ? () => undefined + : (v) => { + if (typeof v[Symbol.toPrimitive] === "function") { + return v[Symbol.toPrimitive] + } + + return undefined + } + +/** + * Attempt to convert an object to the required primitive type. + * @param {object} obj + * @param {"string"|"number"|"bigint"} type + * @returns {string|number|bigint|undefined} + */ +export function toPrimitive(obj, type) { + if (typeof obj !== "object" || typeof obj !== "function") { + return undefined + } + + try { + let val = _toPrimitive(obj)(type) + if (typeof val === type) return val + + val = obj.valueOf() + if (typeof val === type) return val + + } finally { + return undefined + } +} + diff --git a/package.json b/package.json index a36d5ed..96c5b5b 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "license": "MIT", "scripts": { "build": "gulp", - "test": "./node_modules/mocha/bin/mocha test", + "test": "yarn build && ./node_modules/mocha/bin/mocha test", "debug": "./node_modules/mocha/bin/mocha test --inspect-brk" }, "devDependencies": { diff --git a/src/filtrex.mjs b/src/filtrex.mjs index a8687a9..30323cd 100644 --- a/src/filtrex.mjs +++ b/src/filtrex.mjs @@ -1,36 +1,63 @@ // the parser is dynamically generated from generateParser.js at compile time -import { parser } from './parser.mjs'; +import { parser } from './parser.mjs' +import { hasOwnProperty, toPrimitive } from './utils.mjs' // Shared utility functions const std = { isfn: function(fns, funcName) { - return fns.hasOwnProperty(funcName) && typeof fns[funcName] === "function"; + return hasOwnProperty(fns, funcName) && typeof fns[funcName] === "function"; }, unknown: function(funcName) { - throw ReferenceError('Unknown function: ' + funcName + '()'); + throw new ReferenceError('Unknown function: ' + funcName + '()'); }, coerceArray: function(value) { - if (Array.isArray(value)) + if (value === undefined || value === null) { + throw new TypeError(`Expected a list, but got ${value} instead.`) + } + + if (Array.isArray(value)) { return value; - else + } else { return [value]; + } + }, + + coerceNumber: function (value) { + const origValue = value + + if (value === undefined || value === null) + throw new TypeError(`Expected a numeric value, but got ${value} instead.`) + + if (Array.isArray(value) && value.length === 1) + value = value[0] + + if (typeof value === 'object') + value = toPrimitive(value) + + if (typeof value === 'number' || typeof value === 'bigint') + return value; + + throw new TypeError(`Expected a numeric value, but got an ${typeof origValue} instead.`) }, coerceBoolean: function(value) { if (typeof value === 'boolean') - return +value; - else - return value; + return value + + if (typeof value === 'object' && value instanceof Boolean) + return value.valueOf(); + + throw new TypeError(`Expected a boolean (“true” or “false”) value, but got an ${typeof value} instead.`) }, isSubset: function(a, b) { const A = std.coerceArray(a); const B = std.coerceArray(b); - return +A.every( val => B.includes(val) ); + return A.every( val => B.includes(val) ); }, buildString: function(quote, literal) @@ -106,11 +133,13 @@ export function compileExpression(expression, options) { random: Math.random, round: Math.round, sqrt: Math.sqrt, + exists: (v) => v !== undefined && v !== null, + empty: (v) => v === undefined || v === null || v === '' || Array.isArray(v) && v.length === 0 }; if (extraFunctions) { for (var name in extraFunctions) { - if (extraFunctions.hasOwnProperty(name)) { + if (hasOwnProperty(extraFunctions, name)) { functions[name] = extraFunctions[name]; } } @@ -139,17 +168,17 @@ export function compileExpression(expression, options) { // Metaprogramming functions function prop(name, obj) { - return Object.prototype.hasOwnProperty.call(obj||{}, name) ? obj[name] : undefined; + return hasOwnProperty(obj||{}, name) ? obj[name] : undefined; } function safeGetter(obj) { return function get(name) { - return Object.prototype.hasOwnProperty.call(obj||{}, name) ? obj[name] : undefined; + return hasOwnProperty(obj||{}, name) ? obj[name] : undefined; } } if (typeof customProp === 'function') { - prop = (name, obj) => std.coerceBoolean(customProp(name, safeGetter(obj), obj)); + prop = (name, obj) => customProp(name, safeGetter(obj), obj); } diff --git a/src/generateParser.js b/src/generateParser.js index 7b1cadb..3cec9e2 100644 --- a/src/generateParser.js +++ b/src/generateParser.js @@ -1,6 +1,6 @@ const Jison = require("./lib/jison").Jison; -function code(args, skipParentheses) { +function _code(args, skipParentheses) { var argsJs = args.map(function(a) { return typeof(a) == 'number' ? ('$' + a) : JSON.stringify(a); }).join(','); @@ -10,7 +10,36 @@ function code(args, skipParentheses) { : '$$ = ["(", ' + argsJs + ', ")"];'; } -var grammar = { +function code(fragments, ...params) { + const args = [] + + for (let i = 0; i < fragments.length - 1; i++) { + args.push(fragments[i]) + args.push(params[i]) + } + + args.push(fragments[fragments.length - 1]) + + return _code(args, false) +} + +function parenless(fragments, ...params) { + const args = [] + + for (let i = 0; i < fragments.length - 1; i++) { + args.push(fragments[i]) + args.push(params[i]) + } + + args.push(fragments[fragments.length - 1]) + + return _code(args, true) +} + +const bool = "std.coerceBoolean" +const num = "std.coerceNumber" + +const grammar = { // Lexical tokens lex: { rules: [ @@ -85,46 +114,46 @@ var grammar = { ['e EOF', 'return $1;'] ], e: [ - ['e + e' , code([1, '+', 3])], - ['e - e' , code([1, '-', 3])], - ['e * e' , code([1, '*', 3])], - ['e / e' , code([1, '/', 3])], - ['e % e' , code([1, '%', 3])], - ['e ^ e' , code(['Math.pow(', 1, ',', 3, ')'])], - ['- e' , code(['-', 2]), {prec: 'UMINUS'}], - ['e and e', code(['Number(', 1, '&&', 3, ')'])], - ['e or e' , code(['Number(', 1, '||', 3, ')'])], - ['not e' , code(['Number(!', 2, ')'])], - ['e == e' , code(['Number(', 1, '==', 3, ')'])], - ['e != e' , code(['Number(', 1, '!=', 3, ')'])], - ['e ~= e' , code(['Number(RegExp(', 3, ').test(', 1, '))'])], - ['e < e' , code(['Number(', 1, '<' , 3, ')'])], - ['e <= e' , code(['Number(', 1, '<=', 3, ')'])], - ['e > e' , code(['Number(', 1, '> ', 3, ')'])], - ['e >= e' , code(['Number(', 1, '>=', 3, ')'])], - ['e ? e : e', code([1, '?', 3, ':', 5])], - ['( e )' , code([2])], - ['( array , e )', code(['[', 2, ',', 4, ']'])], - ['NUMBER' , code([1])], - ['STRING' , code([1])], - ['SYMBOL' , code(['prop(', 1, ', data)'])], - ['SYMBOL of e', code(['prop(', 1, ',', 3, ')'])], - ['SYMBOL ( )', code(['(std.isfn(fns, ', 1, ') ? fns[', 1, ']() : std.unknown(', 1, '))'])], - ['SYMBOL ( argsList )', code(['(std.isfn(fns, ', 1, ') ? fns[', 1, '](', 3, ') : std.unknown(', 1, '))'])], - ['e in e', code(['std.isSubset(', 1, ', ', 3, ')'])], - ['e not in e', code(['+!std.isSubset(', 1, ', ', 4, ')'])], + ['e + e' , code`${1} + ${3}`], + ['e - e' , code`${1} - ${3}`], + ['e * e' , code`${1} * ${3}`], + ['e / e' , code`${1} / ${3}`], + ['e % e' , code`${1} % ${3}`], + ['e ^ e' , code`Math.pow( ${1}, ${3} )`], + ['- e' , code`- ${2}`, {prec: 'UMINUS'}], + ['e and e', code`${bool}(${1}) && ${bool}(${3})`], + ['e or e' , code`${bool}(${1}) || ${bool}(${3})`], + ['not e' , code`! ${bool}(${2})`], + ['e == e' , code`${1} === ${3}`], + ['e != e' , code`${1} !== ${3}`], + ['e ~= e' , code`RegExp(${3}).test(${1})`], + ['e < e' , code`${1} < ${3}`], + ['e <= e' , code`${1} <= ${3}`], + ['e > e' , code`${1} > ${3}`], + ['e >= e' , code`${1} >= ${3}`], + ['e ? e : e', code`${1} ? ${3} : ${5}`], + ['( e )' , code`${2}`], + ['( array , e )', code`[ ${2}, ${4} ]`], + ['NUMBER' , code`${1}`], + ['STRING' , code`${1}`], + ['SYMBOL' , code`prop(${1}, data)`], + ['SYMBOL of e', code`prop(${1}, ${3})`], + ['SYMBOL ( )', code`std.isfn(fns, ${1}) ? fns[${1}]() : std.unknown(${1})`], + ['SYMBOL ( argsList )', code`std.isfn(fns, ${1}) ? fns[${1}](${3}) : std.unknown(${1})`], + ['e in e', code`std.isSubset(${1}, ${3})`], + ['e not in e', code`!std.isSubset(${1}, ${4})`], ], argsList: [ - ['e', code([1], true)], - ['argsList , e', code([1, ',', 3], true)], + ['e', parenless`${1}`], + ['argsList , e', parenless`${1}, ${3}`], ], inSet: [ - ['e', code(['o ==', 1], true)], - ['inSet , e', code([1, '|| o ==', 3], true)], + ['e', parenless`o === ${1}`], + ['inSet , e', parenless`${1} || o === ${3}`], ], array: [ - ['e', code([1])], - ['array , e', code([1, ',', 3], true)], + ['e', parenless`${1}`], + ['array , e', parenless`${1}, ${3}`], ], } }; diff --git a/src/utils.mjs b/src/utils.mjs new file mode 100644 index 0000000..db17884 --- /dev/null +++ b/src/utils.mjs @@ -0,0 +1,50 @@ +/** + * Determines whether an object has a property with the specified name. + * @param {object} obj the object to be checked + * @param {string|number} prop property name + */ +export function hasOwnProperty(obj, prop) { + if (typeof obj === "object" || typeof obj === "function") { + return Object.prototype.hasOwnProperty.call(obj, prop) + } + + return false +} + +/** + * Safe getter for `v[Symbol.toPrimitive]`. + */ +const _toPrimitive = + typeof Symbol !== "function" || typeof Symbol.toPrimitive !== "symbol" + ? () => undefined + : (v) => { + if (typeof v[Symbol.toPrimitive] === "function") { + return v[Symbol.toPrimitive] + } + + return undefined + } + +/** + * Attempt to convert an object to the required primitive type. + * @param {object} obj + * @param {"string"|"number"|"bigint"} type + * @returns {string|number|bigint|undefined} + */ +export function toPrimitive(obj, type) { + if (typeof obj !== "object" || typeof obj !== "function") { + return undefined + } + + try { + let val = _toPrimitive(obj)(type) + if (typeof val === type) return val + + val = obj.valueOf() + if (typeof val === type) return val + + } finally { + return undefined + } +} + diff --git a/test/arithmetics.js b/test/arithmetics.js index 12ab824..aa9f6d9 100644 --- a/test/arithmetics.js +++ b/test/arithmetics.js @@ -35,7 +35,7 @@ describe('Arithmetics', () => { it('supports functions with multiple args', () => { - expect( eval('random() >= 0') ).equals(1); + expect( eval('random() >= 0') ).equals(true); expect( eval('min(2)') ).equals(2); expect( eval('max(2)') ).equals(2); expect( eval('min(2, 5)') ).equals(2); @@ -52,43 +52,45 @@ describe('Arithmetics', () => { it('can do comparisons', () => { - expect( eval('foo == 4', {foo: 4}) ).equals(1); - expect( eval('foo == 4', {foo: 3}) ).equals(0); - expect( eval('foo == 4', {foo:-4}) ).equals(0); - expect( eval('foo != 4', {foo: 4}) ).equals(0); - expect( eval('foo != 4', {foo: 3}) ).equals(1); - expect( eval('foo != 4', {foo:-4}) ).equals(1); - expect( eval('foo > 4', {foo: 3}) ).equals(0); - expect( eval('foo > 4', {foo: 4}) ).equals(0); - expect( eval('foo > 4', {foo: 5}) ).equals(1); - expect( eval('foo >= 4', {foo: 3}) ).equals(0); - expect( eval('foo >= 4', {foo: 4}) ).equals(1); - expect( eval('foo >= 4', {foo: 5}) ).equals(1); - expect( eval('foo < 4', {foo: 3}) ).equals(1); - expect( eval('foo < 4', {foo: 4}) ).equals(0); - expect( eval('foo < 4', {foo: 5}) ).equals(0); - expect( eval('foo <= 4', {foo: 3}) ).equals(1); - expect( eval('foo <= 4', {foo: 4}) ).equals(1); - expect( eval('foo <= 4', {foo: 5}) ).equals(0); + expect( eval('foo == 4', {foo: 4}) ).equals(true); + expect( eval('foo == 4', {foo: 3}) ).equals(false); + expect( eval('foo == 4', {foo:-4}) ).equals(false); + expect( eval('foo != 4', {foo: 4}) ).equals(false); + expect( eval('foo != 4', {foo: 3}) ).equals(true); + expect( eval('foo != 4', {foo:-4}) ).equals(true); + expect( eval('foo > 4', {foo: 3}) ).equals(false); + expect( eval('foo > 4', {foo: 4}) ).equals(false); + expect( eval('foo > 4', {foo: 5}) ).equals(true); + expect( eval('foo >= 4', {foo: 3}) ).equals(false); + expect( eval('foo >= 4', {foo: 4}) ).equals(true); + expect( eval('foo >= 4', {foo: 5}) ).equals(true); + expect( eval('foo < 4', {foo: 3}) ).equals(true); + expect( eval('foo < 4', {foo: 4}) ).equals(false); + expect( eval('foo < 4', {foo: 5}) ).equals(false); + expect( eval('foo <= 4', {foo: 3}) ).equals(true); + expect( eval('foo <= 4', {foo: 4}) ).equals(true); + expect( eval('foo <= 4', {foo: 5}) ).equals(false); }); it('can do boolean logic', () => { - expect( eval('0 and 0') ).equals(0); - expect( eval('0 and 1') ).equals(0); - expect( eval('1 and 0') ).equals(0); - expect( eval('1 and 1') ).equals(1); - expect( eval('0 or 0') ).equals(0); - expect( eval('0 or 1') ).equals(1); - expect( eval('1 or 0') ).equals(1); - expect( eval('1 or 1') ).equals(1); - expect( eval('not 0') ).equals(1); - expect( eval('not 1') ).equals(0); - expect( eval('(0 and 1) or 1') ).equals(1); - expect( eval('0 and (1 or 1)') ).equals(0); - expect( eval('0 and 1 or 1') ).equals(1); - expect( eval('1 or 1 and 0') ).equals(1); - expect( eval('not 1 and 0') ).equals(0); + const obj = { T: true, F: false }; + + expect( eval('F and F', obj) ).equals(false); + expect( eval('F and T', obj) ).equals(false); + expect( eval('T and F', obj) ).equals(false); + expect( eval('T and T', obj) ).equals(true); + expect( eval('F or F', obj) ).equals(false); + expect( eval('F or T', obj) ).equals(true); + expect( eval('T or F', obj) ).equals(true); + expect( eval('T or T', obj) ).equals(true); + expect( eval('not F', obj) ).equals(true); + expect( eval('not T', obj) ).equals(false); + expect( eval('(F and T) or T', obj) ).equals(true); + expect( eval('F and (T or T)', obj) ).equals(false); + expect( eval('F and T or T', obj) ).equals(true); + expect( eval('T or T and F', obj) ).equals(true); + expect( eval('not T and F', obj) ).equals(false); }); }); \ No newline at end of file diff --git a/test/misc.js b/test/misc.js index 2f54291..93d544c 100644 --- a/test/misc.js +++ b/test/misc.js @@ -20,35 +20,35 @@ describe('Various other things', () => { it('in / not in', () => { // value in array - expect( eval('5 in (1, 2, 3, 4)') ).equals(0); - expect( eval('3 in (1, 2, 3, 4)') ).equals(1); - expect( eval('5 not in (1, 2, 3, 4)') ).equals(1); - expect( eval('3 not in (1, 2, 3, 4)') ).equals(0); + expect( eval('5 in (1, 2, 3, 4)') ).equals(false); + expect( eval('3 in (1, 2, 3, 4)') ).equals(true); + expect( eval('5 not in (1, 2, 3, 4)') ).equals(true); + expect( eval('3 not in (1, 2, 3, 4)') ).equals(false); // array in array - expect( eval('(1, 2) in (1, 2, 3)') ).equals(1); - expect( eval('(1, 2) in (2, 3, 1)') ).equals(1); - expect( eval('(3, 4) in (1, 2, 3)') ).equals(0); - expect( eval('(1, 2) not in (1, 2, 3)') ).equals(0); - expect( eval('(1, 2) not in (2, 3, 1)') ).equals(0); - expect( eval('(3, 4) not in (1, 2, 3)') ).equals(1); + expect( eval('(1, 2) in (1, 2, 3)') ).equals(true); + expect( eval('(1, 2) in (2, 3, 1)') ).equals(true); + expect( eval('(3, 4) in (1, 2, 3)') ).equals(false); + expect( eval('(1, 2) not in (1, 2, 3)') ).equals(false); + expect( eval('(1, 2) not in (2, 3, 1)') ).equals(false); + expect( eval('(3, 4) not in (1, 2, 3)') ).equals(true); // other edge cases - expect( eval('(1, 2) in 1' ) ).equals(0); - expect( eval('1 in 1' ) ).equals(1); - expect( eval('(1, 2) not in 1') ).equals(1); - expect( eval('1 not in 1' ) ).equals(0); + expect( eval('(1, 2) in 1' ) ).equals(false); + expect( eval('1 in 1' ) ).equals(true); + expect( eval('(1, 2) not in 1') ).equals(true); + expect( eval('1 not in 1' ) ).equals(false); }); it('string support', () => { - expect( eval('foo == "hello"', {foo:'hello'}) ).equals(1); - expect( eval('foo == "hello"', {foo:'bye' }) ).equals(0); - expect( eval('foo != "hello"', {foo:'hello'}) ).equals(0); - expect( eval('foo != "hello"', {foo:'bye' }) ).equals(1); - expect( eval('foo in ("aa", "bb")', {foo:'aa'}) ).equals(1); - expect( eval('foo in ("aa", "bb")', {foo:'cc'}) ).equals(0); - expect( eval('foo not in ("aa", "bb")', {foo:'aa'}) ).equals(0); - expect( eval('foo not in ("aa", "bb")', {foo:'cc'}) ).equals(1); + expect( eval('foo == "hello"', {foo:'hello'}) ).equals(true); + expect( eval('foo == "hello"', {foo:'bye' }) ).equals(false); + expect( eval('foo != "hello"', {foo:'hello'}) ).equals(false); + expect( eval('foo != "hello"', {foo:'bye' }) ).equals(true); + expect( eval('foo in ("aa", "bb")', {foo:'aa'}) ).equals(true); + expect( eval('foo in ("aa", "bb")', {foo:'cc'}) ).equals(false); + expect( eval('foo not in ("aa", "bb")', {foo:'aa'}) ).equals(false); + expect( eval('foo not in ("aa", "bb")', {foo:'cc'}) ).equals(true); expect( eval(`"\n"`) ).equals("\n"); expect( eval(`"\u0000"`) ).equals("\u0000"); @@ -56,8 +56,8 @@ describe('Various other things', () => { }); it('regexp support', () => { - expect( eval('foo ~= "^[hH]ello"', {foo:'hello'}) ).equals(1); - expect( eval('foo ~= "^[hH]ello"', {foo:'bye' }) ).equals(0); + expect( eval('foo ~= "^[hH]ello"', {foo:'hello'}) ).equals(true); + expect( eval('foo ~= "^[hH]ello"', {foo:'bye' }) ).equals(false); }); it('array support', () => { @@ -87,7 +87,7 @@ describe('Various other things', () => { it('custom property function basics', () => { expect( compileExpression('a', { customProp: name => name === 'a' })() - ).equals(1); + ).equals(true); expect( compileExpression('a + bb + ccc', { customProp: name => name.length })() @@ -99,13 +99,13 @@ describe('Various other things', () => { ).equals(7); expect( - compileExpression('a', { customProp: (name, get) => get(name) })({ a:true }) - ).equals(1); + compileExpression('a', { customProp: (name, get) => get(name) })({ a: true }) + ).equals(true); - let object = {a:1}; + let object = {a: 2}; expect( compileExpression('a', { customProp: (_,__,obj) => obj === object })(object) - ).equals(1); + ).equals(true); }); it('custom property function text search', () => { @@ -114,12 +114,12 @@ describe('Various other things', () => { let evalProp = exp => compileExpression(exp, { customProp: doesTextMatch })(); - expect( evalProp('able and was and i') ).equals(1); - expect( evalProp('able and was and dog') ).equals(0); - expect( evalProp('able or dog') ).equals(1); - expect( evalProp('able') ).equals(1); - expect( evalProp('Rain and (missing or MAINLY)') ).equals(1); - expect( evalProp('NotThere or missing or falls and plain') ).equals(1); + expect( evalProp('able and was and i') ).equals(true); + expect( evalProp('able and was and dog') ).equals(false); + expect( evalProp('able or dog') ).equals(true); + expect( evalProp('able') ).equals(true); + expect( evalProp('Rain and (missing or MAINLY)') ).equals(true); + expect( evalProp('NotThere or missing or falls and plain') ).equals(true); }); it('custom property function proxy', () => { diff --git a/test/security.js b/test/security.js index 64b62c3..5299f17 100644 --- a/test/security.js +++ b/test/security.js @@ -80,7 +80,7 @@ describe('Security', () => { it('in() is not vulnerable to Object.prototype extensions ', () => { Object.prototype.aa = true; - expect( compileExpression('"aa" in ("bb", "cc")')() ).equals(0); + expect( compileExpression('"aa" in ("bb", "cc")')() ).equals(false); delete Object.prototype.aa; });