package de.congrace.exp4j;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Stack;
import de.congrace.exp4j.FunctionToken.Function;
/**
* this classed is used to create custom functions for exp4j<br/>
* <br/>
* <b>Example</b><br/>
* <code><pre>{@code
* CustomFunction fooFunc = new CustomFunction("foo") {
* public double applyFunction(double value) {
* return value*Math.E;
* }
* };
* double varX=12d;
* Calculable calc = new ExpressionBuilder("foo(x)").withCustomFunction(fooFunc).withVariable("x",varX).build();
* assertTrue(calc.calculate() == Math.E * varX);
* }</pre></code>
*
* @author ruckus
*
*/
public abstract class CustomFunction extends CalculationToken {
private int argc=1;
/**
* create a new single value input CustomFunction with a set name
*
* @param value
* the name of the function (e.g. foo)
*/
protected CustomFunction(String value) throws InvalidCustomFunctionException{
super(value);
for (Function f:Function.values()) {
if (value.equalsIgnoreCase(f.toString())){
throw new InvalidCustomFunctionException(value + " is already reserved as a function name");
}
}
}
/**
* create a new single value input CustomFunction with a set name
*
* @param value
* the name of the function (e.g. foo)
*/
protected CustomFunction(String value,int argumentCount) throws InvalidCustomFunctionException{
super(value);
this.argc=argumentCount;
for (Function f:Function.values()) {
if (value.equalsIgnoreCase(f.toString())){
throw new InvalidCustomFunctionException(value + " is already reserved as a function name");
}
}
}
/**
* apply the function to a value
*
* @param values
* the values to which the function should be applied.
* @return the function value
*/
public abstract Variable applyFunction(List<Variable> vars);
@Override
void mutateStackForCalculation(Stack<Variable> stack, VariableSet variables) {
List<Variable> args = new ArrayList<Variable>(argc);
for (int i=0; i < argc; i++) {
args.add(i, stack.pop() );
}
Collections.reverse(args); // Put elements in logical order
stack.push(this.applyFunction(args));
}
@Override
void mutateStackForInfixTranslation(Stack<Token> operatorStack, StringBuilder output) {
operatorStack.push(this);
}
public int getArgumentCount() {
return argc;
}
}