package de.congrace.exp4j; import java.util.Collection; import java.util.HashSet; import java.util.Set; /** * This is Builder implementation for the exp4j API used to create a Calculable * instance for the user * * @author ruckus * */ public class ExpressionBuilder { private VariableSet variables = new VariableSet(); private final Set<CustomFunction> customFunctions = new HashSet<CustomFunction>(); private String expression; /** * Create a new ExpressionBuilder * * @param expression * the expression to evaluate */ public ExpressionBuilder(String expression) { this.expression = expression; } /** * build a new {@link Calculable} from the expression using the supplied * variables * * @return the {@link Calculable} which can be used to evaluate the * expression * @throws UnknownFunctionException * when an unrecognized function name is used in the expression * @throws UnparsableExpressionException * if the expression could not be parsed */ public Calculable build() throws UnknownFunctionException, UnparsableExpressionException { if (expression.indexOf('=') == -1 && !variables.isEmpty()) { // User supplied an expression without leading "f(...)=" // so we just append the user function to a proper "f()=" // for PostfixExpression.fromInfix() StringBuilder function = new StringBuilder("f("); for (String name : variables.getVariableNames()) { function.append(name).append(','); } expression = function.deleteCharAt(function.length() - 1).toString() + ")=" + expression; } // create the PostfixExpression and return it as a Calculable PostfixExpression delegate = PostfixExpression.fromInfix(expression, customFunctions); for (Variable var : variables ) { delegate.setVariable(var); for (CustomFunction fn:customFunctions){ if (fn.getValue().equalsIgnoreCase(var.getName())){ throw new UnparsableExpressionException("variable '" + var + "' cannot have the same name as a custom function " + fn.getValue()); } } } return delegate; } /** * add a custom function instance for the evaluator to recognize * * @param function * the {@link CustomFunction} to add * @return the {@link ExpressionBuilder} instance */ public ExpressionBuilder withCustomFunction(CustomFunction function) { customFunctions.add(function); return this; } public ExpressionBuilder withCustomFunctions(Collection<CustomFunction> functions) { customFunctions.addAll(functions); return this; } /** * set the value for a variable * * @param variableName * the variable name e.g. "x" * @param value * the value e.g. 2.32d * @return the {@link ExpressionBuilder} instance */ public ExpressionBuilder withVariable(Variable value) { variables.add(value); return this; } /* * Provided for backwards compatibility */ @Deprecated public ExpressionBuilder withVariable(String variableName, double value) { variables.add(new Variable(variableName, value)); return this; } /** * set the variables names used in the expression without setting their * values. Usefull for building an expression before you know the variable values. * * @param variableNames * vararg {@link String} of the variable names used in the * expression * @return the ExpressionBuilder instance */ public ExpressionBuilder withVariableNames(String... variableNames) { for (String name : variableNames) { variables.add( new Variable(name, Double.NaN) ); } return this; } /** * set the values for variables * * @param variableMap * a map of variable names to variable values * @return the {@link ExpressionBuilder} instance */ public ExpressionBuilder withVariables(VariableSet myVariables) { this.variables = myVariables; return this; } }