/* * Copyright 2008 Reg Whitton * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.java.dev.eval; import java.math.BigDecimal; import java.math.MathContext; abstract class Operator { /** * End of string reached. */ static final Operator END = new Operator(-1, 0, null, null, null) { @Override BigDecimal perform(BigDecimal value1, BigDecimal value2, BigDecimal value3) { throw new RuntimeException("END is a dummy operation"); } }; /** * condition ? (expression if true) : (expression if false) */ static final Operator TERNARY = new Operator(0, 3, "?", null, null) { @Override BigDecimal perform(BigDecimal value1, BigDecimal value2, BigDecimal value3) { return (value1.signum() != 0) ? value2 : value3; } }; /** * && */ static final Operator AND = new Operator(0, 2, "&&", Type.BOOLEAN, Type.BOOLEAN) { @Override BigDecimal perform(BigDecimal value1, BigDecimal value2, BigDecimal value3) { return value1.signum() != 0 && value2.signum() != 0 ? BigDecimal.ONE : BigDecimal.ZERO; } }; /** * || */ static final Operator OR = new Operator(0, 2, "||", Type.BOOLEAN, Type.BOOLEAN) { @Override BigDecimal perform(BigDecimal value1, BigDecimal value2, BigDecimal value3) { return value1.signum() != 0 || value2.signum() != 0 ? BigDecimal.ONE : BigDecimal.ZERO; } }; /** * > */ static final Operator GT = new Operator(1, 2, ">", Type.BOOLEAN, Type.ARITHMETIC) { @Override BigDecimal perform(BigDecimal value1, BigDecimal value2, BigDecimal value3) { return value1.compareTo(value2) > 0 ? BigDecimal.ONE : BigDecimal.ZERO; } }; /** * >= */ static final Operator GE = new Operator(1, 2, ">=", Type.BOOLEAN, Type.ARITHMETIC) { @Override BigDecimal perform(BigDecimal value1, BigDecimal value2, BigDecimal value3) { return value1.compareTo(value2) >= 0 ? BigDecimal.ONE : BigDecimal.ZERO; } }; /** * < */ static final Operator LT = new Operator(1, 2, "<", Type.BOOLEAN, Type.ARITHMETIC) { @Override BigDecimal perform(BigDecimal value1, BigDecimal value2, BigDecimal value3) { return value1.compareTo(value2) < 0 ? BigDecimal.ONE : BigDecimal.ZERO; } }; /** * <= */ static final Operator LE = new Operator(1, 2, "<=", Type.BOOLEAN, Type.ARITHMETIC) { @Override BigDecimal perform(BigDecimal value1, BigDecimal value2, BigDecimal value3) { return value1.compareTo(value2) <= 0 ? BigDecimal.ONE : BigDecimal.ZERO; } }; /** * == */ static final Operator EQ = new Operator(1, 2, "==", Type.BOOLEAN, Type.ARITHMETIC) { @Override BigDecimal perform(BigDecimal value1, BigDecimal value2, BigDecimal value3) { return value1.compareTo(value2) == 0 ? BigDecimal.ONE : BigDecimal.ZERO; } }; /** * != or <> */ static final Operator NE = new Operator(1, 2, "!=", Type.BOOLEAN, Type.ARITHMETIC) { @Override BigDecimal perform(BigDecimal value1, BigDecimal value2, BigDecimal value3) { return value1.compareTo(value2) != 0 ? BigDecimal.ONE : BigDecimal.ZERO; } }; /** * + */ static final Operator ADD = new Operator(2, 2, "+", Type.ARITHMETIC, Type.ARITHMETIC) { @Override BigDecimal perform(BigDecimal value1, BigDecimal value2, BigDecimal value3) { return value1.add(value2); } }; /** * - */ static final Operator SUB = new Operator(2, 2, "-", Type.ARITHMETIC, Type.ARITHMETIC) { @Override BigDecimal perform(BigDecimal value1, BigDecimal value2, BigDecimal value3) { return value1.subtract(value2); } }; /** * / */ static final Operator DIV = new Operator(3, 2, "/", Type.ARITHMETIC, Type.ARITHMETIC) { @Override BigDecimal perform(BigDecimal value1, BigDecimal value2, BigDecimal value3) { return value1.divide(value2, MathContext.DECIMAL128); } }; /** * % */ static final Operator REMAINDER = new Operator(3, 2, "%", Type.ARITHMETIC, Type.ARITHMETIC) { @Override BigDecimal perform(BigDecimal value1, BigDecimal value2, BigDecimal value3) { return value1.remainder(value2, MathContext.DECIMAL128); } }; /** * * */ static final Operator MUL = new Operator(3, 2, "*", Type.ARITHMETIC, Type.ARITHMETIC) { @Override BigDecimal perform(BigDecimal value1, BigDecimal value2, BigDecimal value3) { return value1.multiply(value2); } }; /** * -negate */ static final Operator NEG = new Operator(4, 1, "-", Type.ARITHMETIC, Type.ARITHMETIC) { @Override BigDecimal perform(BigDecimal value1, BigDecimal value2, BigDecimal value3) { return value1.negate(); } }; /** * +plus */ static final Operator PLUS = new Operator(4, 1, "+", Type.ARITHMETIC, Type.ARITHMETIC) { @Override BigDecimal perform(BigDecimal value1, BigDecimal value2, BigDecimal value3) { return value1; } }; /** * abs */ static final Operator ABS = new Operator(4, 1, " abs ", Type.ARITHMETIC, Type.ARITHMETIC) { @Override BigDecimal perform(BigDecimal value1, BigDecimal value2, BigDecimal value3) { return value1.abs(); } }; /** * pow */ static final Operator POW = new Operator(4, 2, " pow ", Type.ARITHMETIC, Type.ARITHMETIC) { @Override BigDecimal perform(BigDecimal value1, BigDecimal value2, BigDecimal value3) { try { return value1.pow(value2.intValueExact()); } catch (ArithmeticException ae) { throw new RuntimeException("pow argument: " + ae.getMessage()); } } }; /** * int */ static final Operator INT = new Operator(4, 1, "int ", Type.ARITHMETIC, Type.ARITHMETIC) { @Override BigDecimal perform(BigDecimal value1, BigDecimal value2, BigDecimal value3) { return new BigDecimal(value1.toBigInteger()); } }; /** * No operation - used internally when expression contains only a reference to a variable. */ static final Operator NOP = new Operator(4, 1, "", Type.ARITHMETIC, Type.ARITHMETIC) { @Override BigDecimal perform(BigDecimal value1, BigDecimal value2, BigDecimal value3) { return value1; } }; final int precedence; final int numberOfOperands; final String string; final Type resultType; final Type operandType; Operator(final int precedence, final int numberOfOperands, final String string, final Type resultType, final Type operandType) { this.precedence = precedence; this.numberOfOperands = numberOfOperands; this.string = string; this.resultType = resultType; this.operandType = operandType; } abstract BigDecimal perform(BigDecimal value1, BigDecimal value2, BigDecimal value3); }