essy-evaluator
Advanced tools
Comparing version 1.1.0 to 1.1.1
@@ -104,2 +104,3 @@ (function (global, factory) { | ||
':' : 1, | ||
'.' : 1, | ||
',' : 1, | ||
@@ -214,3 +215,4 @@ '<' : 1, | ||
// Number. Numbers include exponentials. Numbers can start with a decimal point or digit. | ||
else if (c >= '0' && c <= '9' || c === '.') { | ||
// The '.' operator also can be used with arrays so don't count that as a number. | ||
else if (c >= '0' && c <= '9' || (c === '.' && !(i > 0 && (txt.charAt(i-1) === ']' || txt.charAt(i-1) === ')')))) { | ||
str = c; | ||
@@ -354,3 +356,2 @@ i += 1; | ||
/** | ||
@@ -404,4 +405,4 @@ * Simple single-depth extend utility function. | ||
* Evaluates expressions. | ||
* @class Evaluator | ||
* @constructor | ||
* @class Evaluator | ||
* @constructor | ||
* | ||
@@ -478,3 +479,3 @@ ****************************************************************/ | ||
} | ||
if (names) { | ||
@@ -488,2 +489,3 @@ this.defineNames(names); | ||
this.advance(); | ||
var s = this.expression(0); | ||
@@ -529,3 +531,3 @@ return s.ev(); | ||
defineFunction: function (id, ev, noArgs) { | ||
this.defineSymbol(id, extend({ | ||
this.defineSymbol(id, { | ||
nud: function () { | ||
@@ -544,2 +546,3 @@ this.args = []; | ||
this.evaluator.advance(')'); | ||
return this; | ||
@@ -556,4 +559,9 @@ }, | ||
return values; | ||
} | ||
}, { ev: ev })); | ||
}, | ||
argArray: function () { | ||
var a = this.argValue(0); | ||
return typeof a === 'object' ? a : this.argValues(); | ||
}, | ||
ev: ev | ||
}); | ||
}, | ||
@@ -565,6 +573,7 @@ | ||
* @param functions {Object} Keys are function names and values are evaluation functions. | ||
* @param noArgs {Boolean} True if functions don't take arguments. | ||
*/ | ||
defineFunctions: function (functions) { | ||
defineFunctions: function (functions, noArgs) { | ||
for (var f in functions) { | ||
this.defineFunction(f, functions[f]); | ||
this.defineFunction(f, functions[f], noArgs); | ||
} | ||
@@ -720,2 +729,4 @@ }, | ||
'TRUE' : 1, | ||
'false' : 0, | ||
'true' : 1, | ||
'E' : Math.E, | ||
@@ -749,5 +760,19 @@ 'LN2' : Math.log(2), | ||
nud: function () { | ||
var s = this.evaluator.expression(0); | ||
this.evaluator.advance(']'); | ||
return s; | ||
this.elements = []; | ||
while (1) { | ||
this.elements.push(this.evaluator.expression(0)); | ||
if (this.evaluator.activeSymbol.id !== ',') { | ||
break; | ||
} | ||
this.evaluator.advance(','); | ||
} | ||
this.evaluator.advance(']'); | ||
return this; | ||
}, | ||
ev: function () { | ||
var a = []; | ||
for (var i = 0; i < this.elements.length; i++) { | ||
a.push(this.elements[i].ev()); | ||
} | ||
return a; | ||
} | ||
@@ -766,5 +791,13 @@ }, | ||
// Define infix operators. | ||
this.defineInfixOperators({ | ||
'.': { | ||
lbp: 80, | ||
ev: function () { | ||
return this.second.ev(this.firstValue()); | ||
} | ||
}, | ||
'+': { | ||
@@ -914,4 +947,5 @@ lbp: 50, | ||
'and': function () { | ||
for (var i = 0; i < this.args.length; i++) { | ||
if (this.argValue(i) <= 0) { | ||
var args = this.argArray(); | ||
for (var i = 0; i < args.length; i++) { | ||
if (args[i] <= 0) { | ||
return 0; | ||
@@ -967,3 +1001,3 @@ } | ||
}, | ||
'fac': function () { | ||
@@ -1009,3 +1043,3 @@ function fac (x) { | ||
'max': function () { | ||
return Math.max.apply(null, this.argValues()); | ||
return Math.max.apply(null, this.argArray()); | ||
}, | ||
@@ -1016,3 +1050,3 @@ | ||
var sum = 0, | ||
values = this.argValues(); | ||
values = this.argArray(); | ||
@@ -1026,3 +1060,3 @@ for (var i = 0; i < values.length; i++) { | ||
'median': function () { | ||
var values = this.argValues().sort(function (a, b) { | ||
var values = this.argArray().sort(function (a, b) { | ||
return a - b; | ||
@@ -1039,3 +1073,3 @@ }); | ||
'min': function () { | ||
return Math.min.apply(null, this.argValues()); | ||
return Math.min.apply(null, this.argArray()); | ||
}, | ||
@@ -1059,4 +1093,5 @@ | ||
'or': function () { | ||
for (var i = 0, n = this.args.length; i < n; i++) { | ||
if (this.argValue(i) > 0) { | ||
var args = this.argArray(); | ||
for (var i = 0, n = args.length; i < n; i++) { | ||
if (args[i] > 0) { | ||
return 1; | ||
@@ -1074,3 +1109,3 @@ } | ||
var product = 1, | ||
values = this.argValues(); | ||
values = this.argArray(); | ||
for (var i = 0; i < values.length; i++) { | ||
@@ -1126,3 +1161,3 @@ product *= values[i]; | ||
var sum = 0, | ||
values = this.argValues(); | ||
values = this.argArray(); | ||
@@ -1145,2 +1180,155 @@ for (var i = 0; i < values.length; i++) { | ||
}, true); | ||
// Define array functions. | ||
this.defineFunctions({ | ||
'everyA': function (a) { | ||
var fn = this.argValue(0), | ||
result = true; | ||
for (var i = 0; i < a.length; i++) { | ||
result = result && this.evaluator.evaluate(fn + '(' + a[i] + ')'); | ||
} | ||
return result ? 1 : 0; | ||
}, | ||
'filterA': function (a) { | ||
var fn = this.argValue(0), | ||
result = []; | ||
for (var i = 0; i < a.length; i++) { | ||
if (this.evaluator.evaluate(fn + '(' + a[i] + ')')) { | ||
result.push(a[i]); | ||
} | ||
} | ||
return result; | ||
}, | ||
'includesA': function (a) { | ||
var x = this.argValue(0); | ||
for (var i = 0; i < a.length; i++) { | ||
if (a[i] === x) return 1; | ||
} | ||
return 0; | ||
}, | ||
'joinA': function (a) { | ||
return a.join(this.argValue(0)); | ||
}, | ||
'mapA': function (a) { | ||
var fn = this.argValue(0), | ||
result = []; | ||
for (var i = 0; i < a.length; i++) { | ||
result.push(this.evaluator.evaluate(fn + '(' + a[i] + ')')); | ||
} | ||
return result; | ||
}, | ||
'reduceA': function (a) { | ||
var fn = this.argValue(0), | ||
acc = this.args.length === 2 ? this.argValue(1) : a[0]; | ||
for (var i = 0; i < a.length; i++) { | ||
acc = this.evaluator.evaluate(fn + '(' + acc + ',' + a[i] + ',' + i + ',' + a + ')'); | ||
} | ||
return acc; | ||
}, | ||
'sliceA': function (a) { | ||
var to = this.args.length > 1 ? this.argValue(1) : 'undefined'; | ||
return a.slice(this.argValue(0), to); | ||
}, | ||
'someA': function (a) { | ||
var fn = this.argValue(0); | ||
for (var i = 0; i < a.length; i++) { | ||
if (this.evaluator.evaluate(fn + '(' + a[i] + ')')) { | ||
return 1; | ||
} | ||
} | ||
return 0; | ||
} | ||
}); | ||
// Array functions that don't take arguments. | ||
this.defineFunctions({ | ||
'andA': function (a) { | ||
for (var i = 0; i < a.length; i++) { | ||
if (a[i] <= 0) return 0; | ||
} | ||
return 1; | ||
}, | ||
'maxA': function (a) { | ||
return Math.max.apply(null, a); | ||
}, | ||
'meanA': function (a) { | ||
var sum = 0; | ||
for (var i = 0; i < a.length; i++) { | ||
sum += a[i]; | ||
} | ||
return sum / a.length; | ||
}, | ||
'medianA': function (a) { | ||
a = a.sort(function (a, b) { | ||
return a - b; | ||
}); | ||
var len = a.length; | ||
if (len % 2 === 0) { | ||
return (a[len / 2 - 1] + a[len / 2]) / 2; | ||
} | ||
else { | ||
return (a[(len - 1) / 2]); | ||
} | ||
}, | ||
'minA': function (a) { | ||
return Math.min.apply(null, a); | ||
}, | ||
'orA': function (a) { | ||
for (var i = 0; i < a.length; i++) { | ||
if (a[i] > 0) return 1; | ||
} | ||
return 0; | ||
}, | ||
'productA': function (a) { | ||
var product = 1; | ||
for (var i = 0; i < a.length; i++) { | ||
product *= a[i]; | ||
} | ||
return product; | ||
}, | ||
'reverseA': function (a) { | ||
return a.reverse(); | ||
}, | ||
'sumA': function (a) { | ||
var sum = 0; | ||
for (var i = 0; i < a.length; i++) { | ||
sum += a[i]; | ||
} | ||
return sum; | ||
} | ||
}, true); | ||
}, | ||
@@ -1147,0 +1335,0 @@ |
@@ -1,1 +0,1 @@ | ||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.essyExpr=e()}(this,function(){"use strict";function t(t,e){this.type=t,this.message=e}function e(t,e){this.type=t,this.message=e}function n(t){t=t||{},this.operators=a,this.updateOperators(t.operators||{})}function i(t,e){if(e)for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n]);return t}function r(){this.symbolTable={},this.tokenIndex=0,this.tokenSet=null,this.activeSymbol=null,this.defineSymbols()}t.prototype.toString=function(){return this.type+": "+this.message},t.TYPE_ARGUMENT_RANGE="Argument Range",t.TYPE_BAD_TOKEN="Bad Token",t.TYPE_DIVIDE_BY_ZERO="Divide by Zero",t.TYPE_UNDEFINED_SYMBOL="Undefined Symbol",module.exports=t,e.prototype.toString=function(){return this.type+": "+this.message},e.TYPE_INVALID_EXPONENT="Invalid Exponent",e.TYPE_INVALID_NUMBER="Invalid Number",e.TYPE_INVALID_OPERATOR="Invalid Operator",e.TYPE_TRAILING_OPERATOR="Trailing Operator",e.TYPE_UNTERMINATED_STRING="Unterminated String",module.exports=e;var a={"(":1,")":1,"[":1,"]":1,"+":1,"-":1,"*":1,"/":1,"^":1,"%":1,"?":1,":":1,",":1,"<":1,"<=":1,">":1,">=":1,"==":1,"!=":1,"!":1,"&&":1,"||":1};n.prototype.updateOperators=function(t){for(var e in t)this.operators[e]=t[e];this.opPrefix="",this.opSuffix="";for(var n in this.operators)n.length>1&&(this.opPrefix+=n[0],this.opSuffix+=n[n.length-1])},n.prototype.parse=function(t){var n,i,r,a,s=0,o=t.length,u=[],h=function(t,e){return{type:t,value:e}};if(!(t=String(t)))return[];for(n=t.charAt(s);n;)if(n<=" ")s+=1,n=t.charAt(s);else if(n>="a"&&n<="z"||n>="A"&&n<="Z"||"_"===n){for(a=n,s+=1;(n=t.charAt(s))>="a"&&n<="z"||n>="A"&&n<="Z"||n>="0"&&n<="9"||"_"===n;)a+=n,s+=1;u.push(h("name",a))}else if(n>="0"&&n<="9"||"."===n){for(a=n,s+=1;!((n=t.charAt(s))<"0"||n>"9");)s+=1,a+=n;if("."===n)for(s+=1,a+=n;!((n=t.charAt(s))<"0"||n>"9");)s+=1,a+=n;if("e"===n||"E"===n){if(s+=1,a+=n,"-"!==(n=t.charAt(s))&&"+"!==n||(s+=1,a+=n,n=t.charAt(s)),n<"0"||n>"9")throw new e(e.TYPE_INVALID_EXPONENT,a+n);do{s+=1,a+=n,n=t.charAt(s)}while(n>="0"&&n<="9")}if(n>="a"&&n<="z")throw new e(e.TYPE_INVALID_NUMBER,a+n);if(i=+a,!isFinite(i))throw new e(e.TYPE_INVALID_NUMBER,a);u.push(h("number",i))}else if("'"===n||'"'===n){for(a="",r=n,s+=1;;){if((n=t.charAt(s))<" ")throw new e(e.TYPE_UNTERMINATED_STRING,a);if(n===r)break;a+=n,s+=1}s+=1,u.push(h("string",a)),n=t.charAt(s)}else if(this.opPrefix.indexOf(n)>=0){for(a=n,s+=1;s<o&&(n=t.charAt(s),!(this.opSuffix.indexOf(n)<0));)a+=n,s+=1;if(!this.operators[a])throw new e(e.TYPE_INVALID_OPERATOR,a);if(u.push(h("operator",a)),s>=o)throw new e(e.TYPE_TRAILING_OPERATOR,a)}else{if(s+=1,!this.operators[n])throw new e(e.TYPE_INVALID_OPERATOR,n);if(u.push(h("operator",n)),s>=o&&")"!==n&&"]"!==n)throw new e(e.TYPE_TRAILING_OPERATOR,n);n=t.charAt(s)}return u},module.exports=n;var s="(end)";r.prototype={advance:function(e){var n,i;if(e&&this.activeSymbol&&this.activeSymbol.id!==e)throw new t(t.TYPE_BAD_TOKEN,'Expected token with id "'+e+'".');if(this.tokenIndex>=this.tokenSet.length)return this.activeSymbol=this.symbolTable[s],this.activeSymbol;if(i=this.tokenSet[this.tokenIndex],this.tokenIndex+=1,"number"===i.type||"string"===i.type)n=this.symbolTable["(literal)"],this.activeSymbol=Object.create(n),this.activeSymbol.value=i.value;else{if(!(n=this.symbolTable[i.value]))throw new t(t.TYPE_UNDEFINED_SYMBOL,'The symbol "'+i.value+'" is not defined.');this.activeSymbol=Object.create(n)}return this.activeSymbol},evaluate:function(t,e){if("string"==typeof t){t=(new n).parse(t)}e&&this.defineNames(e),this.tokenSet=t,this.tokenIndex=0,this.activeSymbol=0,this.advance();return this.expression(0).ev()},expression:function(t){var e,n=this.activeSymbol;for(this.advance(),e=n.nud();t<this.activeSymbol.lbp;)n=this.activeSymbol,this.advance(),e=n.led(e);return e},defineFunction:function(t,e,n){this.defineSymbol(t,i({nud:function(){if(this.args=[],this.evaluator.advance("("),!n)for(;;){if(this.args.push(this.evaluator.expression(0)),","!=this.evaluator.activeSymbol.id)break;this.evaluator.advance(",")}return this.evaluator.advance(")"),this},argValue:function(t){return this.args[t].ev()},argValues:function(){for(var t=[],e=0;e<this.args.length;e++)t.push(this.args[e].ev());return t}},{ev:e}))},defineFunctions:function(t){for(var e in t)this.defineFunction(e,t[e])},defineInfixOperator:function(t,e,n){this.defineSymbol(t,i({lbp:e,led:function(t){return this.first=t,this.second=this.evaluator.expression(this.lbp),this},firstValue:function(){return this.first.ev()},secondValue:function(){return this.second.ev()}},n))},defineInfixOperators:function(t){for(var e in t){var n=t[e],i={};for(var r in n)"lbp"!==r&&(i[r]=n[r]);this.defineInfixOperator(e,n.lbp,i)}},defineInfixROperator:function(t,e,n){this.defineSymbol(t,{lbp:e,led:function(t){return this.first=t,this.second=this.evaluator.expression(this.lbp-1),this},ev:n})},defineInfixROperators:function(t){for(var e in t)this.defineInfixROperator(e,t[e].lbp,t[e].ev)},defineName:function(t,e){this.defineSymbol(t,{value:e,ev:function(){return this.value}})},defineNames:function(t){for(var e in t)this.defineName(e,t[e])},definePrefixOperator:function(t,e){this.defineSymbol(t,i({nud:function(){return this.first=this.evaluator.expression(70),this}},e))},definePrefixOperators:function(t){for(var e in t)this.definePrefixOperator(e,t[e])},defineSymbols:function(){var e=this;[":",",",")","]","}",s].forEach(function(t){e.defineSymbol(t)}),this.defineNames({FALSE:0,TRUE:1,E:Math.E,LN2:Math.log(2),LN10:Math.log(10),PI:Math.PI,SQRT1_2:1/Math.sqrt(2),SQRT2:Math.sqrt(2)}),this.defineName("(literal)",0),this.definePrefixOperators({"!":{ev:function(){return this.first.ev()>0?0:1}},"(":{nud:function(){var t=this.evaluator.expression(0);return this.evaluator.advance(")"),t}},"[":{nud:function(){var t=this.evaluator.expression(0);return this.evaluator.advance("]"),t}},"{":{nud:function(){var t=this.evaluator.expression(0);return this.evaluator.advance("}"),t}}}),this.defineInfixOperators({"+":{lbp:50,ev:function(){return this.firstValue()+this.secondValue()}},"-":{lbp:50,nud:function(){return this.first=this.evaluator.expression(70),this.isPrefix=!0,this},ev:function(){return this.isPrefix?-this.firstValue():this.firstValue()-this.secondValue()}},"*":{lbp:60,ev:function(){return this.firstValue()*this.secondValue()}},"/":{lbp:60,ev:function(){var e=this.secondValue();if(0===e)throw new t(t.TYPE_DIVIDE_BY_ZERO,'Attempt to divide by 0 using the "/" operator.');return this.firstValue()/e}},"^":{lbp:70,ev:function(){return Math.pow(this.firstValue(),this.secondValue())}},"==":{lbp:40,ev:function(){return this.firstValue()===this.secondValue()?1:0}},"!=":{lbp:40,ev:function(){return this.firstValue()===this.secondValue()?0:1}},"<":{lbp:40,ev:function(){return this.firstValue()<this.secondValue()?1:0}},"<=":{lbp:40,ev:function(){return this.firstValue()<=this.secondValue()?1:0}},">":{lbp:40,ev:function(){return this.firstValue()>this.secondValue()?1:0}},">=":{lbp:40,ev:function(){return this.firstValue()>=this.secondValue()?1:0}},"?":{lbp:20,led:function(t){return this.first=t,this.second=this.evaluator.expression(0),this.evaluator.advance(":"),this.third=this.evaluator.expression(0),this},ev:function(){return this.firstValue()?this.secondValue():this.third.ev()}}}),this.defineInfixROperators({"&&":{lbp:30,ev:function(){return this.first.ev()&&this.second.ev()?1:0}},"||":{lbp:30,ev:function(){return this.first.ev()||this.second.ev()?1:0}}}),this.defineFunctions({abs:function(){return Math.abs(this.argValue(0))},acos:function(){var e=this.argValue(0);if(e<-1||e>1)throw new t(t.TYPE_ARGUMENT_RANGE,'At "acos('+e+')": argument must be in range [-1, 1].');return Math.acos(e)},and:function(){for(var t=0;t<this.args.length;t++)if(this.argValue(t)<=0)return 0;return 1},asin:function(){var e=this.argValue(0);if(e<0||e>1)throw new t(t.TYPE_ARGUMENT_RANGE,'At "asin('+e+')": argument must be in range [0, 1].');return Math.asin(e)},atan:function(){var e=this.argValue(0);if(e<-1||e>1)throw new t(t.TYPE_ARGUMENT_RANGE,'At "atan('+e+')": argument must be in range [-1, 1].');return Math.atan(e)},ceiling:function(){return Math.ceil(this.argValue(0))},choose:function(){var e=this.argValue(0);if(e<1||e>this.args.length)throw new t(t.TYPE_ARGUMENT_RANGE,'At "choose('+e+',...)": the index is out of bounds.');return this.argValue(e)},cos:function(){return Math.cos(this.argValue(0))},exp:function(){return Math.exp(this.argValue(0))},fac:function(){function t(e){return e<0?-1:0===e?1:e*t(e-1)}return t(this.argValue(0))},floor:function(){return Math.floor(this.argValue(0))},if:function(){return this.argValue(0)>0?this.argValue(1):this.argValue(2)},log:function(){var e=this.argValue(0);if(e<=0)throw new t(t.TYPE_ARGUMENT_RANGE,'At "log('+e+')": argument must be greater than 0.');return Math.log(10)/Math.log(e)},ln:function(){var e=this.argValue(0);if(e<=0)throw new t(t.TYPE_ARGUMENT_RANGE,'At "ln('+e+')": argument must be greater than 0.');return Math.log(e)},max:function(){return Math.max.apply(null,this.argValues())},mean:function(){for(var t=0,e=this.argValues(),n=0;n<e.length;n++)t+=e[n];return t/e.length},median:function(){var t=this.argValues().sort(function(t,e){return t-e});return t.length%2==0?(t[t.length/2-1]+t[t.length/2])/2:t[(t.length-1)/2]},min:function(){return Math.min.apply(null,this.argValues())},mod:function(){var e=this.argValue(1);if(0===e)throw new t(t.TYPE_DIVIDE_BY_ZERO,'At "mod('+e+')": cannot divide by 0.');return this.argValue(0)%e},not:function(){return this.argValue(0)>0?0:1},or:function(){for(var t=0,e=this.args.length;t<e;t++)if(this.argValue(t)>0)return 1;return 0},pow:function(){return Math.pow(this.argValue(0),this.argValue(1))},product:function(){for(var t=1,e=this.argValues(),n=0;n<e.length;n++)t*=e[n];return t},quotient:function(){var e=this.argValue(0),n=this.argValue(1);if(0===n)throw new t(t.TYPE_DIVIDE_BY_ZERO,'At "quotient('+e+", "+n+')": cannot divide by 0.');return Math.floor(e/n)},randInt:function(){var t=this.argValue(0);return t+parseInt(Math.random()*(this.argValue(1)-t))},randRange:function(){var t=this.argValue(0);return t+Math.random()*(this.argValue(1)-t)},round:function(){return Math.round(this.argValue(0))},sin:function(){return Math.sin(this.argValue(0))},sqrt:function(){var e=this.argValue(0);if(e<=0)throw new t(t.TYPE_ARGUMENT_RANGE,'At "sqrt('+e+')": argument must be greater than 0.');return Math.sqrt(e)},sum:function(){for(var t=0,e=this.argValues(),n=0;n<e.length;n++)t+=e[n];return t},tan:function(){return Math.tan(this.argValue(0))}}),this.defineFunction("rand",function(){return Math.random()},!0)},defineSymbol:function(t,e){(e=e||{}).evaluator=this,this.symbolTable[t]=function(t,e){return i(Object.create({id:t,lbp:0,nud:function(){return this},led:function(){return this},ev:function(){return 0}}),e)}(t,e)},deleteSymbol:function(t){return delete this.symbolTable[t]}};return{Evaluator:r,EvaluateException:t,Parser:n,ParseException:e}}); | ||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.essyExpr=e()}(this,function(){"use strict";function t(t,e){this.type=t,this.message=e}function e(t,e){this.type=t,this.message=e}function n(t){t=t||{},this.operators=a,this.updateOperators(t.operators||{})}function r(t,e){if(e)for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n]);return t}function i(){this.symbolTable={},this.tokenIndex=0,this.tokenSet=null,this.activeSymbol=null,this.defineSymbols()}t.prototype.toString=function(){return this.type+": "+this.message},t.TYPE_ARGUMENT_RANGE="Argument Range",t.TYPE_BAD_TOKEN="Bad Token",t.TYPE_DIVIDE_BY_ZERO="Divide by Zero",t.TYPE_UNDEFINED_SYMBOL="Undefined Symbol",module.exports=t,e.prototype.toString=function(){return this.type+": "+this.message},e.TYPE_INVALID_EXPONENT="Invalid Exponent",e.TYPE_INVALID_NUMBER="Invalid Number",e.TYPE_INVALID_OPERATOR="Invalid Operator",e.TYPE_TRAILING_OPERATOR="Trailing Operator",e.TYPE_UNTERMINATED_STRING="Unterminated String",module.exports=e;var a={"(":1,")":1,"[":1,"]":1,"+":1,"-":1,"*":1,"/":1,"^":1,"%":1,"?":1,":":1,".":1,",":1,"<":1,"<=":1,">":1,">=":1,"==":1,"!=":1,"!":1,"&&":1,"||":1};n.prototype.updateOperators=function(t){for(var e in t)this.operators[e]=t[e];this.opPrefix="",this.opSuffix="";for(var n in this.operators)n.length>1&&(this.opPrefix+=n[0],this.opSuffix+=n[n.length-1])},n.prototype.parse=function(t){var n,r,i,a,s=0,u=t.length,o=[],h=function(t,e){return{type:t,value:e}};if(!(t=String(t)))return[];for(n=t.charAt(s);n;)if(n<=" ")s+=1,n=t.charAt(s);else if(n>="a"&&n<="z"||n>="A"&&n<="Z"||"_"===n){for(a=n,s+=1;(n=t.charAt(s))>="a"&&n<="z"||n>="A"&&n<="Z"||n>="0"&&n<="9"||"_"===n;)a+=n,s+=1;o.push(h("name",a))}else if(n>="0"&&n<="9"||"."===n&&(!(s>0)||"]"!==t.charAt(s-1)&&")"!==t.charAt(s-1))){for(a=n,s+=1;!((n=t.charAt(s))<"0"||n>"9");)s+=1,a+=n;if("."===n)for(s+=1,a+=n;!((n=t.charAt(s))<"0"||n>"9");)s+=1,a+=n;if("e"===n||"E"===n){if(s+=1,a+=n,"-"!==(n=t.charAt(s))&&"+"!==n||(s+=1,a+=n,n=t.charAt(s)),n<"0"||n>"9")throw new e(e.TYPE_INVALID_EXPONENT,a+n);do{s+=1,a+=n,n=t.charAt(s)}while(n>="0"&&n<="9")}if(n>="a"&&n<="z")throw new e(e.TYPE_INVALID_NUMBER,a+n);if(r=+a,!isFinite(r))throw new e(e.TYPE_INVALID_NUMBER,a);o.push(h("number",r))}else if("'"===n||'"'===n){for(a="",i=n,s+=1;;){if((n=t.charAt(s))<" ")throw new e(e.TYPE_UNTERMINATED_STRING,a);if(n===i)break;a+=n,s+=1}s+=1,o.push(h("string",a)),n=t.charAt(s)}else if(this.opPrefix.indexOf(n)>=0){for(a=n,s+=1;s<u&&(n=t.charAt(s),!(this.opSuffix.indexOf(n)<0));)a+=n,s+=1;if(!this.operators[a])throw new e(e.TYPE_INVALID_OPERATOR,a);if(o.push(h("operator",a)),s>=u)throw new e(e.TYPE_TRAILING_OPERATOR,a)}else{if(s+=1,!this.operators[n])throw new e(e.TYPE_INVALID_OPERATOR,n);if(o.push(h("operator",n)),s>=u&&")"!==n&&"]"!==n)throw new e(e.TYPE_TRAILING_OPERATOR,n);n=t.charAt(s)}return o},module.exports=n;var s="(end)";i.prototype={advance:function(e){var n,r;if(e&&this.activeSymbol&&this.activeSymbol.id!==e)throw new t(t.TYPE_BAD_TOKEN,'Expected token with id "'+e+'".');if(this.tokenIndex>=this.tokenSet.length)return this.activeSymbol=this.symbolTable[s],this.activeSymbol;if(r=this.tokenSet[this.tokenIndex],this.tokenIndex+=1,"number"===r.type||"string"===r.type)n=this.symbolTable["(literal)"],this.activeSymbol=Object.create(n),this.activeSymbol.value=r.value;else{if(!(n=this.symbolTable[r.value]))throw new t(t.TYPE_UNDEFINED_SYMBOL,'The symbol "'+r.value+'" is not defined.');this.activeSymbol=Object.create(n)}return this.activeSymbol},evaluate:function(t,e){if("string"==typeof t){t=(new n).parse(t)}e&&this.defineNames(e),this.tokenSet=t,this.tokenIndex=0,this.activeSymbol=0,this.advance();return this.expression(0).ev()},expression:function(t){var e,n=this.activeSymbol;for(this.advance(),e=n.nud();t<this.activeSymbol.lbp;)n=this.activeSymbol,this.advance(),e=n.led(e);return e},defineFunction:function(t,e,n){this.defineSymbol(t,{nud:function(){if(this.args=[],this.evaluator.advance("("),!n)for(;;){if(this.args.push(this.evaluator.expression(0)),","!=this.evaluator.activeSymbol.id)break;this.evaluator.advance(",")}return this.evaluator.advance(")"),this},argValue:function(t){return this.args[t].ev()},argValues:function(){for(var t=[],e=0;e<this.args.length;e++)t.push(this.args[e].ev());return t},argArray:function(){var t=this.argValue(0);return"object"==typeof t?t:this.argValues()},ev:e})},defineFunctions:function(t,e){for(var n in t)this.defineFunction(n,t[n],e)},defineInfixOperator:function(t,e,n){this.defineSymbol(t,r({lbp:e,led:function(t){return this.first=t,this.second=this.evaluator.expression(this.lbp),this},firstValue:function(){return this.first.ev()},secondValue:function(){return this.second.ev()}},n))},defineInfixOperators:function(t){for(var e in t){var n=t[e],r={};for(var i in n)"lbp"!==i&&(r[i]=n[i]);this.defineInfixOperator(e,n.lbp,r)}},defineInfixROperator:function(t,e,n){this.defineSymbol(t,{lbp:e,led:function(t){return this.first=t,this.second=this.evaluator.expression(this.lbp-1),this},ev:n})},defineInfixROperators:function(t){for(var e in t)this.defineInfixROperator(e,t[e].lbp,t[e].ev)},defineName:function(t,e){this.defineSymbol(t,{value:e,ev:function(){return this.value}})},defineNames:function(t){for(var e in t)this.defineName(e,t[e])},definePrefixOperator:function(t,e){this.defineSymbol(t,r({nud:function(){return this.first=this.evaluator.expression(70),this}},e))},definePrefixOperators:function(t){for(var e in t)this.definePrefixOperator(e,t[e])},defineSymbols:function(){var e=this;[":",",",")","]","}",s].forEach(function(t){e.defineSymbol(t)}),this.defineNames({FALSE:0,TRUE:1,false:0,true:1,E:Math.E,LN2:Math.log(2),LN10:Math.log(10),PI:Math.PI,SQRT1_2:1/Math.sqrt(2),SQRT2:Math.sqrt(2)}),this.defineName("(literal)",0),this.definePrefixOperators({"!":{ev:function(){return this.first.ev()>0?0:1}},"(":{nud:function(){var t=this.evaluator.expression(0);return this.evaluator.advance(")"),t}},"[":{nud:function(){for(this.elements=[];;){if(this.elements.push(this.evaluator.expression(0)),","!==this.evaluator.activeSymbol.id)break;this.evaluator.advance(",")}return this.evaluator.advance("]"),this},ev:function(){for(var t=[],e=0;e<this.elements.length;e++)t.push(this.elements[e].ev());return t}},"{":{nud:function(){var t=this.evaluator.expression(0);return this.evaluator.advance("}"),t}}}),this.defineInfixOperators({".":{lbp:80,ev:function(){return this.second.ev(this.firstValue())}},"+":{lbp:50,ev:function(){return this.firstValue()+this.secondValue()}},"-":{lbp:50,nud:function(){return this.first=this.evaluator.expression(70),this.isPrefix=!0,this},ev:function(){return this.isPrefix?-this.firstValue():this.firstValue()-this.secondValue()}},"*":{lbp:60,ev:function(){return this.firstValue()*this.secondValue()}},"/":{lbp:60,ev:function(){var e=this.secondValue();if(0===e)throw new t(t.TYPE_DIVIDE_BY_ZERO,'Attempt to divide by 0 using the "/" operator.');return this.firstValue()/e}},"^":{lbp:70,ev:function(){return Math.pow(this.firstValue(),this.secondValue())}},"==":{lbp:40,ev:function(){return this.firstValue()===this.secondValue()?1:0}},"!=":{lbp:40,ev:function(){return this.firstValue()===this.secondValue()?0:1}},"<":{lbp:40,ev:function(){return this.firstValue()<this.secondValue()?1:0}},"<=":{lbp:40,ev:function(){return this.firstValue()<=this.secondValue()?1:0}},">":{lbp:40,ev:function(){return this.firstValue()>this.secondValue()?1:0}},">=":{lbp:40,ev:function(){return this.firstValue()>=this.secondValue()?1:0}},"?":{lbp:20,led:function(t){return this.first=t,this.second=this.evaluator.expression(0),this.evaluator.advance(":"),this.third=this.evaluator.expression(0),this},ev:function(){return this.firstValue()?this.secondValue():this.third.ev()}}}),this.defineInfixROperators({"&&":{lbp:30,ev:function(){return this.first.ev()&&this.second.ev()?1:0}},"||":{lbp:30,ev:function(){return this.first.ev()||this.second.ev()?1:0}}}),this.defineFunctions({abs:function(){return Math.abs(this.argValue(0))},acos:function(){var e=this.argValue(0);if(e<-1||e>1)throw new t(t.TYPE_ARGUMENT_RANGE,'At "acos('+e+')": argument must be in range [-1, 1].');return Math.acos(e)},and:function(){for(var t=this.argArray(),e=0;e<t.length;e++)if(t[e]<=0)return 0;return 1},asin:function(){var e=this.argValue(0);if(e<0||e>1)throw new t(t.TYPE_ARGUMENT_RANGE,'At "asin('+e+')": argument must be in range [0, 1].');return Math.asin(e)},atan:function(){var e=this.argValue(0);if(e<-1||e>1)throw new t(t.TYPE_ARGUMENT_RANGE,'At "atan('+e+')": argument must be in range [-1, 1].');return Math.atan(e)},ceiling:function(){return Math.ceil(this.argValue(0))},choose:function(){var e=this.argValue(0);if(e<1||e>this.args.length)throw new t(t.TYPE_ARGUMENT_RANGE,'At "choose('+e+',...)": the index is out of bounds.');return this.argValue(e)},cos:function(){return Math.cos(this.argValue(0))},exp:function(){return Math.exp(this.argValue(0))},fac:function(){function t(e){return e<0?-1:0===e?1:e*t(e-1)}return t(this.argValue(0))},floor:function(){return Math.floor(this.argValue(0))},if:function(){return this.argValue(0)>0?this.argValue(1):this.argValue(2)},log:function(){var e=this.argValue(0);if(e<=0)throw new t(t.TYPE_ARGUMENT_RANGE,'At "log('+e+')": argument must be greater than 0.');return Math.log(10)/Math.log(e)},ln:function(){var e=this.argValue(0);if(e<=0)throw new t(t.TYPE_ARGUMENT_RANGE,'At "ln('+e+')": argument must be greater than 0.');return Math.log(e)},max:function(){return Math.max.apply(null,this.argArray())},mean:function(){for(var t=0,e=this.argArray(),n=0;n<e.length;n++)t+=e[n];return t/e.length},median:function(){var t=this.argArray().sort(function(t,e){return t-e});return t.length%2==0?(t[t.length/2-1]+t[t.length/2])/2:t[(t.length-1)/2]},min:function(){return Math.min.apply(null,this.argArray())},mod:function(){var e=this.argValue(1);if(0===e)throw new t(t.TYPE_DIVIDE_BY_ZERO,'At "mod('+e+')": cannot divide by 0.');return this.argValue(0)%e},not:function(){return this.argValue(0)>0?0:1},or:function(){for(var t=this.argArray(),e=0,n=t.length;e<n;e++)if(t[e]>0)return 1;return 0},pow:function(){return Math.pow(this.argValue(0),this.argValue(1))},product:function(){for(var t=1,e=this.argArray(),n=0;n<e.length;n++)t*=e[n];return t},quotient:function(){var e=this.argValue(0),n=this.argValue(1);if(0===n)throw new t(t.TYPE_DIVIDE_BY_ZERO,'At "quotient('+e+", "+n+')": cannot divide by 0.');return Math.floor(e/n)},randInt:function(){var t=this.argValue(0);return t+parseInt(Math.random()*(this.argValue(1)-t))},randRange:function(){var t=this.argValue(0);return t+Math.random()*(this.argValue(1)-t)},round:function(){return Math.round(this.argValue(0))},sin:function(){return Math.sin(this.argValue(0))},sqrt:function(){var e=this.argValue(0);if(e<=0)throw new t(t.TYPE_ARGUMENT_RANGE,'At "sqrt('+e+')": argument must be greater than 0.');return Math.sqrt(e)},sum:function(){for(var t=0,e=this.argArray(),n=0;n<e.length;n++)t+=e[n];return t},tan:function(){return Math.tan(this.argValue(0))}}),this.defineFunction("rand",function(){return Math.random()},!0),this.defineFunctions({everyA:function(t){for(var e=this.argValue(0),n=!0,r=0;r<t.length;r++)n=n&&this.evaluator.evaluate(e+"("+t[r]+")");return n?1:0},filterA:function(t){for(var e=this.argValue(0),n=[],r=0;r<t.length;r++)this.evaluator.evaluate(e+"("+t[r]+")")&&n.push(t[r]);return n},includesA:function(t){for(var e=this.argValue(0),n=0;n<t.length;n++)if(t[n]===e)return 1;return 0},joinA:function(t){return t.join(this.argValue(0))},mapA:function(t){for(var e=this.argValue(0),n=[],r=0;r<t.length;r++)n.push(this.evaluator.evaluate(e+"("+t[r]+")"));return n},reduceA:function(t){for(var e=this.argValue(0),n=2===this.args.length?this.argValue(1):t[0],r=0;r<t.length;r++)n=this.evaluator.evaluate(e+"("+n+","+t[r]+","+r+","+t+")");return n},sliceA:function(t){var e=this.args.length>1?this.argValue(1):"undefined";return t.slice(this.argValue(0),e)},someA:function(t){for(var e=this.argValue(0),n=0;n<t.length;n++)if(this.evaluator.evaluate(e+"("+t[n]+")"))return 1;return 0}}),this.defineFunctions({andA:function(t){for(var e=0;e<t.length;e++)if(t[e]<=0)return 0;return 1},maxA:function(t){return Math.max.apply(null,t)},meanA:function(t){for(var e=0,n=0;n<t.length;n++)e+=t[n];return e/t.length},medianA:function(t){var e=(t=t.sort(function(t,e){return t-e})).length;return e%2==0?(t[e/2-1]+t[e/2])/2:t[(e-1)/2]},minA:function(t){return Math.min.apply(null,t)},orA:function(t){for(var e=0;e<t.length;e++)if(t[e]>0)return 1;return 0},productA:function(t){for(var e=1,n=0;n<t.length;n++)e*=t[n];return e},reverseA:function(t){return t.reverse()},sumA:function(t){for(var e=0,n=0;n<t.length;n++)e+=t[n];return e}},!0)},defineSymbol:function(t,e){(e=e||{}).evaluator=this,this.symbolTable[t]=function(t,e){return r(Object.create({id:t,lbp:0,nud:function(){return this},led:function(){return this},ev:function(){return 0}}),e)}(t,e)},deleteSymbol:function(t){return delete this.symbolTable[t]}};return{Evaluator:i,EvaluateException:t,Parser:n,ParseException:e}}); |
{ | ||
"name": "essy-evaluator", | ||
"version": "1.1.0", | ||
"version": "1.1.1", | ||
"description": "Parses and evaluates mathematical expressions from Javascript strings.", | ||
@@ -5,0 +5,0 @@ "main": "dist/bundle.js", |
@@ -36,3 +36,3 @@ Javascript Expression Parser and Evaluator | ||
result = evaluator.evaluate('myCustomName / 4'); // 2 | ||
// Equivalently pass custom definitions to evaluate. | ||
@@ -134,3 +134,3 @@ result = evaluator.evaluate('myCustomName / 4', { myCustomName: 8 }); // 2 | ||
If a string `exp` is provided, `evaluate()` will throw a `ParseException` if parsing | ||
If a string `exp` is provided, `evaluate()` will throw a `ParseException` if parsing | ||
fails. See `Parser.parse()` for details. | ||
@@ -153,14 +153,14 @@ | ||
var result; | ||
// Simple evaluation of string. | ||
result = evaluator.evaluate('1 + 2'); // 3 | ||
// Evaluation of tokens. | ||
var tokens = parser.parse('1 + 2'); | ||
result = evaluator.evaluate(tokens); // 3 | ||
// Defining names. | ||
result = evaluator.evaluate('1 + myConstant', { myConstant: 2 }); // 3 | ||
##### defineFunction (name {String}, ev {Function} [, noArgs {Boolean}]) | ||
@@ -252,4 +252,8 @@ Defines a custom function. The `name` is the name for the function and `ev` is | ||
#### Pre-defined Functions | ||
`Evaluator` defines the following functions by default: | ||
`Evaluator` defines the following functions by default. Functions that accept an | ||
arbitrary number of arguments (e.g., `and`, `max`, etc.) will also accept an | ||
array as a single argument. | ||
evaluator.evaluate('and(1,2,3)') === evaluator.evaluate('and([1,2,3])'); | ||
Function | Description | ||
@@ -289,1 +293,82 @@ :--------------------- | :---------- | ||
tan(x) | Returns the tangent of x. | ||
#### Pre-defined Array Functions | ||
`Evaluator` includes various common functions to operate on arrays. Functions | ||
that return arrays can be chained. | ||
##### andA() | ||
Returns 1 if all elements in array are greater than 0, else returns 0. | ||
##### everyA(fn) | ||
Calls `fn` on every element and returns 1 if `fn` returns true in all cases. | ||
evaluator.defineFunction('threshold', function () { | ||
return this.argValue(0) < 5; | ||
}); | ||
result = evaluator.evaluate('[1, 2, 3].everyA("threshold")'); // 1 | ||
result = evaluator.evaluate('[1, 2, 6].everyA("threshold")'); // 0 | ||
##### filterA(fn) | ||
Filters elements using `fn`. | ||
evaluator.defineFunction('myFilter', function () { | ||
return this.argValue(0) < 3; | ||
}); | ||
result = evaluator.evaluate('[1, 2, 4, 5].filterA("myFilter")'); // [1, 2] | ||
##### includesA(x) | ||
Returns 1 if array includes element `x`, else returns 0. | ||
##### joinA(joiner) | ||
Joins array elements into string using `joiner`. | ||
##### mapA(fn) | ||
Maps elements using `fn`. | ||
result = evaluator.evaluate('[1, 2, 3].mapA("fac")'); // [1, 2, 6] | ||
##### maxA() | ||
Returns element with maximum value. | ||
##### meanA() | ||
Returns mean of elements. | ||
##### medianA() | ||
Returns median of elements. | ||
##### minA() | ||
Returns element with minimum value. | ||
##### orA() | ||
Returns 1 if any element is greater than 0. | ||
##### productA() | ||
Returns product of elements. | ||
##### reduceA(fn, acc) | ||
Reduces array using `fn`. An optional initial value for the accumulator can | ||
be specified as `acc`. If not provided the first element in the array will be used. | ||
The provided `fn` accepts four arguments: | ||
- accumulator: Accumulated result. | ||
- currentValue: Value of current array element. | ||
- index: [optional] Index of current array element. | ||
- array: [optional] The array `a`. | ||
evaluator.defineFunction('summer', function () { | ||
// Add accumulator and currentValue. | ||
return this.argValue(0) + this.argValue(1); | ||
}); | ||
result = evaluator.evaluate('[1, 2, 3].reduceA("summer", 0)'); // 6 | ||
##### reverseA() | ||
Returns reversed array. | ||
##### slice(start [,end]) | ||
Returns slice of array. | ||
##### someA(fn) | ||
Returns 1 if `fn` returns true for any element. | ||
##### sumA() | ||
Returns sum of elements. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
59309
1213
370