@Override public ValueList evaluate(RuleEvaluation evaluation, BinaryOperator statement) { switch (statement.getOperator()) { case plus: case minus: case multiply: case divide: case modulo: case exponent: return evaluateArithmeticOperator(evaluation, statement); case gt: case ge: case lt: case le: case eq: case ne: return evaluateRelOpOperator(evaluation, statement); case and: case or: case xor: return evaluateBooleanOperator(evaluation, statement); case matches: return evaluateBooleanConstraint(evaluation, statement); case implies: return evaluateImplies(evaluation, statement); // for all is not listed here; it has more information that just two operands, so it has its // own evaluator // not and exists are unary operators and not handled here } throw new RuntimeException("operation " + statement.getOperator() + " not yet supported"); }
private ValueList evaluateArithmeticOperator( RuleEvaluation evaluation, BinaryOperator statement) { ValueList leftValues = evaluation.evaluate(statement.getLeftOperand()); ValueList rightValues = evaluation.evaluate(statement.getRightOperand()); ValueList possibleNullResult = checkAndHandleNull(leftValues, rightValues); if (possibleNullResult != null) { possibleNullResult.setType(PrimitiveType.Real); return possibleNullResult; } else { ValueList result = new ValueList(); result.setType(PrimitiveType.Real); checkIsNumber(leftValues, rightValues); if (leftValues.size() == rightValues.size()) { for (int i = 0; i < leftValues.size(); i++) { Value leftValue = leftValues.get(i); Value rightValue = rightValues.get(i); evaluateArithmetic( statement, result, rightValue.getValue(), leftValue.getValue(), getPaths(leftValue, rightValue)); } } else if (leftValues.size() == 1) { Value leftValue = leftValues.get(0); for (Value rightValue : rightValues.getValues()) { evaluateArithmetic( statement, result, rightValue.getValue(), leftValue.getValue(), getPaths(leftValue, rightValue)); } } else if (rightValues.size() == 1) { Value rightValue = rightValues.get(0); for (Value leftValue : leftValues.getValues()) { evaluateArithmetic( statement, result, rightValue.getValue(), leftValue.getValue(), getPaths(leftValue, rightValue)); } } else { // TODO: this also happens when one of the modelreferences has a value that does not exist // in the model, but others have - while the rules are correct. Those are very valid cases // how to fix? throw new IllegalArgumentException("sizes of operator arguments not compatible"); } return result; } }
private ValueList evaluateImplies(RuleEvaluation evaluation, BinaryOperator statement) { ValueList leftValue = evaluation.evaluate(statement.getLeftOperand()); if (leftValue.getSingleBooleanResult()) { ValueList rightValue = evaluation.evaluate(statement.getRightOperand()); return rightValue; } else { // if the left operand evaluates to false, the entire result is true, to not violate the // assertion // not sure if this should be the case return new ValueList(true, leftValue.getAllPaths()); } }
private Boolean evaluateBoolean( BinaryOperator statement, Boolean leftBoolean, Boolean rightBoolean) { switch (statement.getOperator()) { case and: return leftBoolean & rightBoolean; case or: return leftBoolean | rightBoolean; case xor: return leftBoolean ^ rightBoolean; default: throw new IllegalArgumentException("Not a boolean operator: " + statement.getOperator()); } }
private ValueList evaluateBooleanConstraint(RuleEvaluation evaluation, BinaryOperator statement) { ValueList leftValues = evaluation.evaluate(statement.getLeftOperand()); if (!(statement.getRightOperand() instanceof Constraint)) { throw new IllegalArgumentException( "cannot evaluate matches statement, right operand not a constraint"); } Constraint constraint = (Constraint) statement.getRightOperand(); ValueList result = new ValueList(); result.setType(PrimitiveType.Boolean); for (Value value : leftValues.getValues()) { result.addValue(constraint.getItem().isValidValue(value.getValue()), value.getPaths()); } return result; }
private Value evaluateRelOp( BinaryOperator statement, Object leftValue, Object rightValue, List<String> paths) { if (leftValue == null || rightValue == null) { return new Value(evaluateNullRelOp(statement.getOperator(), leftValue, rightValue), paths); } else if (leftValue instanceof Long && rightValue instanceof Long) { return new Value( evaluateIntegerRelOp(statement.getOperator(), (Long) leftValue, (Long) rightValue), paths); } else { return new Value( evaluateRealRelOp( statement.getOperator(), convertToDouble(leftValue), convertToDouble(rightValue)), paths); } }
private ValueList evaluateBooleanOperator(RuleEvaluation evaluation, BinaryOperator statement) { ValueList leftValues = evaluation.evaluate(statement.getLeftOperand()); ValueList rightValues = evaluation.evaluate(statement.getRightOperand()); ValueList possibleNullResult = checkAndHandleNull(leftValues, rightValues); if (possibleNullResult != null) { possibleNullResult.setType(PrimitiveType.Boolean); return possibleNullResult; } checkisBoolean(leftValues, rightValues); ValueList result = new ValueList(); result.setType(PrimitiveType.Boolean); if (leftValues.size() == rightValues.size()) { for (int i = 0; i < leftValues.size(); i++) { Value<Boolean> leftValue = leftValues.get(i); Value<Boolean> rightValue = rightValues.get(i); List<String> paths = getPaths(leftValue, rightValue); result.addValue( evaluateBoolean(statement, leftValue.getValue(), rightValue.getValue()), paths); } } else if (leftValues.size() == 1) { Value<Boolean> leftValue = leftValues.get(0); for (Value<Boolean> rightValue : rightValues.getValues()) { List<String> paths = getPaths(leftValue, rightValue); result.addValue( evaluateBoolean(statement, leftValue.getValue(), rightValue.getValue()), paths); } } else if (rightValues.size() == 1) { Value<Boolean> rightValue = rightValues.get(0); for (Value<Boolean> leftValue : leftValues.getValues()) { List<String> paths = getPaths(leftValue, rightValue); result.addValue( evaluateBoolean(statement, leftValue.getValue(), rightValue.getValue()), paths); } } else { throw new IllegalArgumentException("sizes of operator arguments not compatible"); } return result; }
private void evaluateArithmetic( BinaryOperator statement, ValueList result, Object rightValue, Object leftValue, List<String> paths) { if (leftValue instanceof Long && rightValue instanceof Long) { result.addValue( evaluateIntegerArithmetic(statement.getOperator(), (Long) leftValue, (Long) rightValue), paths); result.setType(PrimitiveType.Integer); } else { result.addValue( evaluateRealArithmetic( statement.getOperator(), convertToDouble(leftValue), convertToDouble(rightValue)), paths); result.setType(PrimitiveType.Real); } }
@NotNull private ValueList evaluateRelOpOperator(RuleEvaluation evaluation, BinaryOperator statement) { ValueList leftValues = evaluation.evaluate(statement.getLeftOperand()); ValueList rightValues = evaluation.evaluate(statement.getRightOperand()); ValueList possibleNullResult = handlePossibleNullRelOpResult(statement, leftValues, rightValues); if (possibleNullResult != null) { possibleNullResult.setType(PrimitiveType.Boolean); return possibleNullResult; } else { checkIsNumberOrNull(leftValues, rightValues); ValueList result = new ValueList(); result.setType(PrimitiveType.Boolean); // according to the xpath spec, at least one pair from both collections must exist that // matches the condition. // want otherwise? Use for_all/every result.addValue(evaluateMultipleValuesRelOp(statement, leftValues, rightValues)); return result; } }
private ValueList handlePossibleNullRelOpResult( BinaryOperator statement, ValueList leftValues, ValueList rightValues) { switch (statement.getOperator()) { case eq: case ne: // if null, can be true or false depending on checks return null; case gt: case ge: case lt: case le: // if null, result undefined, return null return checkAndHandleNull(leftValues, rightValues); default: throw new IllegalStateException("unknown relop operator"); } }