blob: c9e7a609f38f330edba5deef239741ebaee657b9 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2014-2015 BSI Business Systems Integration AG.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* BSI Business Systems Integration AG - initial API and implementation
******************************************************************************/
/*
* A simple calculator similar to eval but safe in use.
* Supports the following format:
* group character ( )
* digits 0-9
* operators + - * /
* decimal separator .
* no grouping character
* no whitespace
*/
scout.Calculator = function() {};
scout.Calculator.prototype.isFormula = function(input) {
return input.match(/^[\d\(\)\+\-\*\/\.]+$/);
};
scout.Calculator.prototype.evalFormula = function(input) {
this._tokens = input
.split(/([\d.]+|\(|\)|[\+\-\*\/])/)
.filter(function(e) {
return e.length !== 0;
});
return this._expr();
};
scout.Calculator.prototype._next = function() {
if (this._tokens.length === 0) {
return undefined;
}
return this._tokens[0];
};
scout.Calculator.prototype._consumeNext = function() {
var cur = this._tokens[0];
this._tokens = this._tokens.slice(1, this._tokens.length);
return cur;
};
scout.Calculator.prototype._expr = function() {
return this._sum();
};
//a+b+...
scout.Calculator.prototype._sum = function() {
var v = this._prod();
while (this._next() === '+' || this._next() === '-') {
switch (this._consumeNext()) { // NOSONAR
case '+':
v = v + this._prod();
break;
case '-':
v = v - this._prod();
break;
}
}
return v;
};
//a*b*...
scout.Calculator.prototype._prod = function() {
var v = this._unary();
while (this._next() === '*' || this._next() === '/') {
switch (this._consumeNext()) { // NOSONAR
case '*':
v = v * this._unary();
break;
case '/':
v = v / this._unary();
break;
}
}
return v;
};
//[+-]123, [+-](a)
scout.Calculator.prototype._unary = function() {
var qualifier = 1;
if (this._next() === '+') {
this._consumeNext();
} else if (this._next() === '-') {
this._consumeNext();
qualifier = -1;
}
var v;
if ((v = this._group()) !== undefined) {
return qualifier * v;
}
//must be num
v = this._consumeNext();
return qualifier * v;
};
//(a)
scout.Calculator.prototype._group = function() {
if (this._next() === '(') {
this._consumeNext();
var v = this._expr();
if (this._next() !== ')') {
throw 'missing closing bracket';
}
this._consumeNext();
return v;
}
return undefined;
};