package nl.ipo.cds.validation.logical; import java.util.List; import nl.ipo.cds.validation.Expression; import nl.ipo.cds.validation.ValidationMessage; import nl.ipo.cds.validation.ValidatorContext; import nl.ipo.cds.validation.constants.Constant; import nl.ipo.cds.validation.execute.Compiler; import nl.ipo.cds.validation.execute.CompilerException; import nl.ipo.cds.validation.execute.ExpressionExecutor; import nl.ipo.cds.validation.flow.IfExpression; public class AndExpression<K extends Enum<K> & ValidationMessage<K, C>, C extends ValidatorContext<K, C>> extends AbstractLogicalNAryExpr<K, C> { public final boolean shortCircuit; public AndExpression (final List<Expression<K, C, Boolean>> inputs) { this (inputs, false); } public AndExpression (final List<Expression<K, C, Boolean>> inputs, final boolean shortCircuit) { super (inputs); this.shortCircuit = shortCircuit; } public AndExpression<K, C> shortCircuit () { return new AndExpression<K, C> (inputs, true); } @Override public boolean evaluate (final List<Boolean> inputValues) { for (final Boolean value: inputValues) { if (value == null || !value) { return false; } } return true; } @Override public String toString () { final StringBuilder builder = new StringBuilder (); builder.append ('('); for (final Expression<K, C, Boolean> input: inputs) { if (builder.length () > 1) { builder.append (" and "); } builder.append (input.toString ()); } builder.append (')'); return builder.toString (); } @Override public ExpressionExecutor<C> getExecutor (final Compiler<C> compiler) throws CompilerException { if (!shortCircuit) { return super.getExecutor (compiler); } // Transform the and expression into a sequence of if-else epxressions that implement the early-out: return createIfExpression (inputs).getExecutor (compiler); } private Expression<K, C, Boolean> createIfExpression (final List<Expression<K, C, Boolean>> inputs) { if (inputs.size () == 1) { return inputs.get (0); } else { return new IfExpression<K, C, Boolean> (inputs.get (0), createIfExpression (inputs.subList (1, inputs.size ())), new Constant<K, C, Boolean> (false, Boolean.class)); } } }