org.cqframework.cql.elm.evaluating.SimpleElmEngine Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of elm Show documentation
Show all versions of elm Show documentation
The elm library for the Clinical Quality Language Java reference implementation
package org.cqframework.cql.elm.evaluating;
import org.hl7.elm.r1.*;
import javax.xml.namespace.QName;
import java.math.BigDecimal;
/*
A simple ELM engine that is capable of limited evaluation of ELM
required for static analysis and other optimization use cases (such as
constant folding, data requirements analysis, limited constraint validation,
etc.)
*/
public class SimpleElmEngine {
public SimpleElmEngine() {
}
private boolean literalsEqual(Literal left, Literal right) {
return (left == null && right == null)
|| (left != null && left.getValueType() != null && left.getValueType().equals(right.getValueType()) && stringsEqual(left.getValue(), right.getValue()));
}
public boolean booleansEqual(Expression left, Expression right) {
return expressionsEqual(left, right);
}
public boolean integersEqual(Expression left, Expression right) {
return expressionsEqual(left, right);
}
public boolean decimalsEqual(Expression left, Expression right) {
return expressionsEqual(left, right);
}
public boolean decimalsEqual(BigDecimal left, BigDecimal right) {
if (left == null && right == null) {
return true;
}
if (left == null || right == null) {
return false;
}
return left.equals(right);
}
public boolean quantitiesEqual(Quantity left, Quantity right) {
if (left == null && right == null) {
return true;
}
if (left == null || right == null) {
return true;
}
return decimalsEqual(left.getValue(), right.getValue())
&& stringsEqual(left.getUnit(), right.getUnit());
}
public boolean stringsEqual(Expression left, Expression right) {
return expressionsEqual(left, right);
}
public boolean dateTimesEqual(Expression left, Expression right) {
return expressionsEqual(left, right);
}
public boolean dateRangesEqual(Expression left, Expression right) {
return expressionsEqual(left, right);
}
public boolean stringsEqual(String left, String right) {
return (left == null && right == null) || (left != null && left.equals(right));
}
public boolean systemsEqual(CodeSystemRef left, CodeSystemRef right) {
// TODO: Needs to do the comparison on the URI, but I don't want to have to resolve here
return (left == null && right == null)
|| (left != null && stringsEqual(left.getLibraryName(), right.getLibraryName()) && stringsEqual(left.getName(), right.getName()));
}
public boolean valueSetsEqual(ValueSetRef left, ValueSetRef right) {
// TODO: Needs to do the comparison on the URI, but I don't want to have to resolve here
return (left == null && right == null)
|| (left != null && stringsEqual(left.getLibraryName(), right.getLibraryName()) && stringsEqual(left.getName(), right.getName()));
}
public boolean codesEqual(Expression left, Expression right) {
return expressionsEqual(left, right);
}
public boolean qnamesEqual(QName left, QName right) {
if (left == null && right == null) {
return true;
}
if (left == null || right == null) {
return false;
}
return left.equals(right);
}
public boolean typeSpecifiersEqual(TypeSpecifier left, TypeSpecifier right) {
if (left == null && right == null) {
return true;
}
if (left == null || right == null) {
return false;
}
// NamedTypeSpecifier
if (left instanceof NamedTypeSpecifier) {
if (right instanceof NamedTypeSpecifier) {
NamedTypeSpecifier leftArg = (NamedTypeSpecifier)left;
NamedTypeSpecifier rightArg = (NamedTypeSpecifier)right;
return qnamesEqual(leftArg.getName(), rightArg.getName());
}
return false;
}
// IntervalTypeSpecifier
if (left instanceof IntervalTypeSpecifier) {
if (right instanceof IntervalTypeSpecifier) {
IntervalTypeSpecifier leftArg = (IntervalTypeSpecifier)left;
IntervalTypeSpecifier rightArg = (IntervalTypeSpecifier)right;
return typeSpecifiersEqual(leftArg.getPointType(), rightArg.getPointType());
}
return false;
}
// ListTypeSpecifier
if (left instanceof ListTypeSpecifier) {
if (right instanceof ListTypeSpecifier) {
ListTypeSpecifier leftArg = (ListTypeSpecifier)left;
ListTypeSpecifier rightArg = (ListTypeSpecifier)right;
return typeSpecifiersEqual(leftArg.getElementType(), rightArg.getElementType());
}
return false;
}
// TupleTypeSpecifier
if (left instanceof TupleTypeSpecifier) {
if (right instanceof TupleTypeSpecifier) {
TupleTypeSpecifier leftArg = (TupleTypeSpecifier)left;
TupleTypeSpecifier rightArg = (TupleTypeSpecifier)right;
if (leftArg.getElement() != null && rightArg.getElement() != null && leftArg.getElement().size() == rightArg.getElement().size()) {
for (int i = 0; i < leftArg.getElement().size(); i++) {
TupleElementDefinition leftElement = leftArg.getElement().get(i);
TupleElementDefinition rightElement = rightArg.getElement().get(i);
if (!typeSpecifiersEqual(leftElement.getType(), rightElement.getType())
|| !typeSpecifiersEqual(leftElement.getElementType(), rightElement.getElementType())
|| !stringsEqual(leftElement.getName(), rightElement.getName())) {
return false;
}
}
return true;
}
return false;
}
return false;
}
// ChoiceTypeSpecifier
if (left instanceof ChoiceTypeSpecifier) {
if (right instanceof ChoiceTypeSpecifier) {
ChoiceTypeSpecifier leftArg = (ChoiceTypeSpecifier)left;
ChoiceTypeSpecifier rightArg = (ChoiceTypeSpecifier)right;
if (leftArg.getType() != null && rightArg.getType() != null && leftArg.getType().size() == rightArg.getType().size()) {
for (int i = 0; i < leftArg.getType().size(); i++) {
TypeSpecifier leftType = leftArg.getType().get(i);
TypeSpecifier rightType = rightArg.getType().get(i);
if (!typeSpecifiersEqual(leftType, rightType)) {
return false;
}
}
}
if (leftArg.getChoice() != null && rightArg.getChoice() != null && leftArg.getChoice().size() == rightArg.getChoice().size()) {
for (int i = 0; i < leftArg.getChoice().size(); i++) {
TypeSpecifier leftType = leftArg.getChoice().get(i);
TypeSpecifier rightType = rightArg.getChoice().get(i);
if (!typeSpecifiersEqual(leftType, rightType)) {
return false;
}
}
return true;
}
return false;
}
return false;
}
// False for the possibility of an unrecognized type specifier type
return false;
}
public boolean expressionsEqual(Expression left, Expression right) {
if (left == null && right == null) {
return true;
}
if (left == null || right == null) {
return false;
}
if (left instanceof Literal) {
if (right instanceof Literal) {
return literalsEqual((Literal)left, (Literal)right);
}
return false;
}
if (left instanceof Date) {
if (right instanceof Date) {
Date leftDate = (Date)left;
Date rightDate = (Date)right;
return integersEqual(leftDate.getYear(), rightDate.getYear())
&& integersEqual(leftDate.getMonth(), rightDate.getMonth())
&& integersEqual(leftDate.getDay(), rightDate.getDay());
}
return false;
}
if (left instanceof Time) {
if (right instanceof Time) {
Time leftTime = (Time)left;
Time rightTime = (Time)right;
return integersEqual(leftTime.getHour(), rightTime.getHour())
&& integersEqual(leftTime.getMinute(), rightTime.getMinute())
&& integersEqual(leftTime.getSecond(), rightTime.getSecond())
&& integersEqual(leftTime.getMillisecond(), rightTime.getMillisecond());
}
return false;
}
if (left instanceof DateTime) {
if (right instanceof DateTime) {
DateTime leftDateTime = (DateTime)left;
DateTime rightDateTime = (DateTime)right;
return integersEqual(leftDateTime.getYear(), rightDateTime.getYear())
&& integersEqual(leftDateTime.getMonth(), rightDateTime.getMonth())
&& integersEqual(leftDateTime.getDay(), rightDateTime.getDay())
&& integersEqual(leftDateTime.getHour(), rightDateTime.getHour())
&& integersEqual(leftDateTime.getMinute(), rightDateTime.getMinute())
&& integersEqual(leftDateTime.getSecond(), rightDateTime.getSecond())
&& integersEqual(leftDateTime.getMillisecond(), rightDateTime.getMillisecond())
&& decimalsEqual(leftDateTime.getTimezoneOffset(), rightDateTime.getTimezoneOffset());
}
return false;
}
if (left instanceof Interval) {
if (right instanceof Interval) {
Interval leftInterval = (Interval)left;
Interval rightInterval = (Interval)right;
return booleansEqual(leftInterval.getLowClosedExpression(), rightInterval.getLowClosedExpression())
&& dateTimesEqual(leftInterval.getLow(), rightInterval.getLow())
&& leftInterval.isLowClosed() == rightInterval.isLowClosed()
&& booleansEqual(leftInterval.getHighClosedExpression(), rightInterval.getHighClosedExpression())
&& dateTimesEqual(leftInterval.getHigh(), rightInterval.getHigh())
&& leftInterval.isHighClosed() == rightInterval.isHighClosed();
}
return false;
}
// TODO: Strictly speaking this would need to resolve the parameter library since it's not in the ELM if it's a local parameter reference
if (left instanceof ParameterRef) {
if (right instanceof ParameterRef) {
ParameterRef leftParameter = (ParameterRef)left;
ParameterRef rightParameter = (ParameterRef)right;
return stringsEqual(leftParameter.getLibraryName(), rightParameter.getLibraryName())
&& stringsEqual(leftParameter.getName(), rightParameter.getName());
}
return false;
}
if (left instanceof ValueSetRef) {
if (right instanceof ValueSetRef) {
return valueSetsEqual((ValueSetRef)left, (ValueSetRef)right);
}
return false;
}
if (left instanceof CodeSystemRef) {
if (right instanceof CodeSystemRef) {
return systemsEqual((CodeSystemRef)left, (CodeSystemRef)right);
}
return false;
}
if (left instanceof ConceptRef) {
if (right instanceof ConceptRef) {
ConceptRef leftConcept = (ConceptRef)left;
ConceptRef rightConcept = (ConceptRef)right;
// TODO: Needs to do the comparison on the URI, but I don't want to resolve here
return stringsEqual(leftConcept.getLibraryName(), rightConcept.getLibraryName())
&& stringsEqual(leftConcept.getName(), rightConcept.getName());
}
return false;
}
if (left instanceof CodeRef) {
if (right instanceof CodeRef) {
CodeRef leftCode = (CodeRef)left;
CodeRef rightCode = (CodeRef)right;
// TODO: Needs to do the comparison on the URI, but I don't want to resolve here
return stringsEqual(leftCode.getLibraryName(), rightCode.getLibraryName())
&& stringsEqual(leftCode.getName(), rightCode.getName());
}
return false;
}
if (left instanceof Code) {
if (right instanceof Code) {
Code leftCode = (Code)left;
Code rightCode = (Code)right;
return stringsEqual(leftCode.getCode(), rightCode.getCode())
&& systemsEqual(leftCode.getSystem(), rightCode.getSystem());
}
return false;
}
if (left instanceof Concept) {
if (right instanceof Concept) {
Concept leftConcept = (Concept)left;
Concept rightConcept = (Concept)right;
if (leftConcept.getCode() != null && rightConcept.getCode() != null) {
for (Code lc : leftConcept.getCode()) {
for (Code rc : rightConcept.getCode()) {
if (codesEqual(lc, rc)) {
return true;
}
}
}
}
}
return false;
}
if (left instanceof List) {
if (right instanceof List) {
List leftList = (List)left;
List rightList = (List)right;
// TODO: Potentially use a hashSet to avoid order-dependence here
if (leftList.getElement().size() == rightList.getElement().size()) {
for (int i = 0; i < leftList.getElement().size(); i++) {
if (!codesEqual(leftList.getElement().get(i), rightList.getElement().get(i))) {
return false;
}
}
}
}
return false;
}
if (left instanceof ToList) {
if (right instanceof ToList) {
Expression leftSingleton = ((ToList)left).getOperand();
Expression rightSingleton = ((ToList)right).getOperand();
return codesEqual(leftSingleton, rightSingleton);
}
return false;
}
// Quantity
if (left instanceof Quantity) {
if (right instanceof Quantity) {
return quantitiesEqual((Quantity)left, (Quantity)right);
}
return false;
}
// Ratio
if (left instanceof Ratio) {
if (right instanceof Ratio) {
return quantitiesEqual(((Ratio)left).getDenominator(), ((Ratio)right).getDenominator())
&& quantitiesEqual(((Ratio)left).getNumerator(), ((Ratio)right).getNumerator());
}
return false;
}
// TODO: Consider refactoring ComparableElmRequirement?
// Retrieve
// InCodeSystem
if (left instanceof InCodeSystem) {
if (right instanceof InCodeSystem) {
InCodeSystem inCodeSystemLeft = (InCodeSystem)left;
InCodeSystem inCodeSystemRight = (InCodeSystem)right;
return expressionsEqual(inCodeSystemLeft.getCode(), inCodeSystemRight.getCode())
&& systemsEqual(inCodeSystemLeft.getCodesystem(), inCodeSystemRight.getCodesystem())
&& expressionsEqual(inCodeSystemLeft.getCodesystemExpression(), inCodeSystemRight.getCodesystemExpression());
}
return false;
}
// AnyInCodeSystem
if (left instanceof AnyInCodeSystem) {
if (right instanceof AnyInCodeSystem) {
AnyInCodeSystem anyInCodeSystemLeft = (AnyInCodeSystem)left;
AnyInCodeSystem anyInCodeSystemRight = (AnyInCodeSystem)right;
return expressionsEqual(anyInCodeSystemLeft.getCodes(), anyInCodeSystemRight.getCodes())
&& systemsEqual(anyInCodeSystemLeft.getCodesystem(), anyInCodeSystemRight.getCodesystem())
&& expressionsEqual(anyInCodeSystemLeft.getCodesystemExpression(), anyInCodeSystemRight.getCodesystemExpression());
}
return false;
}
// InValueSet
if (left instanceof InValueSet) {
if (right instanceof InValueSet) {
InValueSet inLeft = (InValueSet)left;
InValueSet inRight = (InValueSet)right;
return expressionsEqual(inLeft.getCode(), inRight.getCode())
&& valueSetsEqual(inLeft.getValueset(), inRight.getValueset())
&& expressionsEqual(inLeft.getValuesetExpression(), inRight.getValuesetExpression());
}
return false;
}
// AnyInValueSet
if (left instanceof AnyInValueSet) {
if (right instanceof AnyInValueSet) {
AnyInValueSet inLeft = (AnyInValueSet)left;
AnyInValueSet inRight = (AnyInValueSet)right;
return expressionsEqual(inLeft.getCodes(), inRight.getCodes())
&& valueSetsEqual(inLeft.getValueset(), inRight.getValueset())
&& expressionsEqual(inLeft.getValuesetExpression(), inRight.getValuesetExpression());
}
return false;
}
// CalculateAge
if (left instanceof CalculateAge) {
if (right instanceof CalculateAge) {
CalculateAge leftArg = (CalculateAge)left;
CalculateAge rightArg = (CalculateAge)right;
return expressionsEqual(leftArg.getOperand(), rightArg.getOperand())
&& leftArg.getPrecision().equals(rightArg.getPrecision());
}
return false;
}
// Subsumes
if (left instanceof Subsumes) {
if (right instanceof Subsumes) {
Subsumes leftArg = (Subsumes)left;
Subsumes rightArg = (Subsumes)right;
if (operandsEqual(leftArg, rightArg)) {
return true;
}
return false;
}
return false;
}
// SubsumedBy
if (left instanceof SubsumedBy) {
if (right instanceof SubsumedBy) {
SubsumedBy leftArg = (SubsumedBy)left;
SubsumedBy rightArg = (SubsumedBy)right;
if (operandsEqual(leftArg, rightArg)) {
return true;
}
return false;
}
return false;
}
// AggregateExpression
if (left instanceof AggregateExpression) {
if (right instanceof AggregateExpression) {
AggregateExpression leftArg = (AggregateExpression)left;
AggregateExpression rightArg = (AggregateExpression)right;
return aggregateExpressionsEqual(leftArg, rightArg);
}
return false;
}
// OperatorExpression
if (left instanceof OperatorExpression) {
if (right instanceof OperatorExpression) {
OperatorExpression leftArg = (OperatorExpression)left;
OperatorExpression rightArg = (OperatorExpression)right;
return operatorExpressionsEqual(leftArg, rightArg);
}
return false;
}
if (!left.getClass().getCanonicalName().equals(right.getClass().getCanonicalName())) {
return false;
}
// AliasRef
if (left instanceof AliasRef) {
if (right instanceof AliasRef) {
AliasRef leftArg = (AliasRef)left;
AliasRef rightArg = (AliasRef)right;
return stringsEqual(leftArg.getName(), rightArg.getName());
}
return false;
}
// Case
if (left instanceof Case) {
if (right instanceof Case) {
Case leftArg = (Case)left;
Case rightArg = (Case)right;
if (!expressionsEqual(leftArg.getComparand(), rightArg.getComparand())) {
return false;
}
if (!expressionsEqual(leftArg.getElse(), rightArg.getElse())) {
return false;
}
if (leftArg.getCaseItem() != null && rightArg.getCaseItem() != null && leftArg.getCaseItem().size() == rightArg.getCaseItem().size()) {
for (int i = 0; i < leftArg.getCaseItem().size(); i++) {
CaseItem leftCaseItem = leftArg.getCaseItem().get(i);
CaseItem rightCaseItem = rightArg.getCaseItem().get(i);
if (!expressionsEqual(leftCaseItem.getWhen(), rightCaseItem.getWhen()) || !expressionsEqual(leftCaseItem.getThen(), rightCaseItem.getThen())) {
return false;
}
}
return true;
}
return false;
}
return false;
}
// Current
if (left instanceof Current) {
if (right instanceof Current) {
Current leftArg = (Current)left;
Current rightArg = (Current)right;
return stringsEqual(leftArg.getScope(), rightArg.getScope());
}
return false;
}
// FunctionRef
if (left instanceof FunctionRef) {
if (right instanceof FunctionRef) {
FunctionRef leftArg = (FunctionRef)left;
FunctionRef rightArg = (FunctionRef)right;
return stringsEqual(leftArg.getLibraryName(), rightArg.getLibraryName())
&& stringsEqual(leftArg.getName(), rightArg.getName())
&& operandsEqual(leftArg, rightArg);
}
}
// ExpressionRef
if (left instanceof ExpressionRef) {
if (right instanceof ExpressionRef) {
ExpressionRef leftArg = (ExpressionRef)left;
ExpressionRef rightArg = (ExpressionRef)right;
return stringsEqual(leftArg.getLibraryName(), rightArg.getLibraryName())
&& stringsEqual(leftArg.getName(), rightArg.getName());
}
return false;
}
// Filter
if (left instanceof Filter) {
if (right instanceof Filter) {
Filter leftArg = (Filter)left;
Filter rightArg = (Filter)right;
return expressionsEqual(leftArg.getSource(), rightArg.getSource())
&& expressionsEqual(leftArg.getCondition(), rightArg.getCondition())
&& stringsEqual(leftArg.getScope(), rightArg.getScope());
}
return false;
}
// ForEach
if (left instanceof ForEach) {
if (right instanceof ForEach) {
ForEach leftArg = (ForEach)left;
ForEach rightArg = (ForEach)right;
return expressionsEqual(leftArg.getSource(), rightArg.getSource())
&& expressionsEqual(leftArg.getElement(), rightArg.getElement())
&& stringsEqual(leftArg.getScope(), rightArg.getScope());
}
return false;
}
// IdentifierRef
if (left instanceof IdentifierRef) {
if (right instanceof IdentifierRef) {
IdentifierRef leftArg = (IdentifierRef)left;
IdentifierRef rightArg = (IdentifierRef)right;
return stringsEqual(leftArg.getLibraryName(), rightArg.getLibraryName())
&& stringsEqual(leftArg.getName(), rightArg.getName());
}
return false;
}
// If
if (left instanceof If) {
if (right instanceof If) {
If leftArg = (If)left;
If rightArg = (If)right;
return expressionsEqual(leftArg.getCondition(), rightArg.getCondition())
&& expressionsEqual(leftArg.getThen(), rightArg.getThen())
&& expressionsEqual(leftArg.getElse(), rightArg.getElse());
}
return false;
}
// Instance
if (left instanceof Instance) {
if (right instanceof Instance) {
Instance leftArg = (Instance)left;
Instance rightArg = (Instance)right;
if (!qnamesEqual(leftArg.getClassType(), rightArg.getClassType())) {
return false;
}
if (leftArg.getElement() != null && rightArg.getElement() != null && leftArg.getElement().size() == rightArg.getElement().size()) {
for (int i = 0; i < leftArg.getElement().size(); i++) {
InstanceElement leftElement = leftArg.getElement().get(i);
InstanceElement rightElement = rightArg.getElement().get(i);
if (!stringsEqual(leftElement.getName(), rightElement.getName()) || !expressionsEqual(leftElement.getValue(), rightElement.getValue())) {
return false;
}
}
return true;
}
return false;
}
return false;
}
// Iteration
if (left instanceof Iteration) {
if (right instanceof Iteration) {
Iteration leftArg = (Iteration)left;
Iteration rightArg = (Iteration)right;
return stringsEqual(leftArg.getScope(), rightArg.getScope());
}
return false;
}
// MaxValue
if (left instanceof MaxValue) {
if (right instanceof MaxValue) {
MaxValue leftArg = (MaxValue)left;
MaxValue rightArg = (MaxValue)right;
return qnamesEqual(leftArg.getValueType(), rightArg.getValueType());
}
return false;
}
// MinValue
if (left instanceof MinValue) {
if (right instanceof MinValue) {
MinValue leftArg = (MinValue)left;
MinValue rightArg = (MinValue)right;
return qnamesEqual(leftArg.getValueType(), rightArg.getValueType());
}
return false;
}
// Null
if (left instanceof Null) {
if (right instanceof Null) {
return true;
}
return false;
}
// OperandRef
if (left instanceof OperandRef) {
if (right instanceof OperandRef) {
OperandRef leftArg = (OperandRef)left;
OperandRef rightArg = (OperandRef)right;
return stringsEqual(leftArg.getName(), rightArg.getName());
}
return false;
}
// Property
if (left instanceof Property) {
if (right instanceof Property) {
Property leftArg = (Property)left;
Property rightArg = (Property)right;
return stringsEqual(leftArg.getScope(), rightArg.getScope())
&& stringsEqual(leftArg.getPath(), rightArg.getPath());
}
return false;
}
// Query
if (left instanceof Query) {
if (right instanceof Query) {
Query leftArg = (Query)left;
Query rightArg = (Query)right;
}
return false;
}
// QueryLetRef
if (left instanceof QueryLetRef) {
if (right instanceof QueryLetRef) {
QueryLetRef leftArg = (QueryLetRef)left;
QueryLetRef rightArg = (QueryLetRef)right;
return stringsEqual(leftArg.getName(), rightArg.getName());
}
return false;
}
// Repeat
if (left instanceof Repeat) {
if (right instanceof Repeat) {
Repeat leftArg = (Repeat)left;
Repeat rightArg = (Repeat)right;
}
return false;
}
// Sort
if (left instanceof Sort) {
if (right instanceof Sort) {
Sort leftArg = (Sort)left;
Sort rightArg = (Sort)right;
}
return false;
}
// Total
if (left instanceof Total) {
if (right instanceof Total) {
Total leftArg = (Total)left;
Total rightArg = (Total)right;
}
return false;
}
// Tuple
if (left instanceof Tuple) {
if (right instanceof Tuple) {
Tuple leftArg = (Tuple)left;
Tuple rightArg = (Tuple)right;
}
return false;
}
return false;
}
public boolean operandsEqual(FunctionRef left, FunctionRef right) {
if (left.getOperand() != null && left.getOperand() != null && left.getOperand().size() == left.getOperand().size()) {
for (int i = 0; i < left.getOperand().size(); i++) {
if (!expressionsEqual(left.getOperand().get(i), right.getOperand().get(i))) {
return false;
}
}
return true;
}
return false;
}
public boolean operandsEqual(BinaryExpression left, BinaryExpression right) {
if (left.getOperand() != null && left.getOperand() != null && left.getOperand().size() == left.getOperand().size()) {
for (int i = 0; i < left.getOperand().size(); i++) {
if (!expressionsEqual(left.getOperand().get(i), right.getOperand().get(i))) {
return false;
}
}
return true;
}
return false;
}
public boolean operandsEqual(TernaryExpression left, TernaryExpression right) {
if (left.getOperand() != null && left.getOperand() != null && left.getOperand().size() == left.getOperand().size()) {
for (int i = 0; i < left.getOperand().size(); i++) {
if (!expressionsEqual(left.getOperand().get(i), right.getOperand().get(i))) {
return false;
}
}
return true;
}
return false;
}
public boolean operandsEqual(NaryExpression left, NaryExpression right) {
if (left.getOperand() != null && left.getOperand() != null && left.getOperand().size() == left.getOperand().size()) {
for (int i = 0; i < left.getOperand().size(); i++) {
if (!expressionsEqual(left.getOperand().get(i), right.getOperand().get(i))) {
return false;
}
}
return true;
}
return false;
}
public boolean operatorExpressionsEqual(OperatorExpression left, OperatorExpression right) {
if (left == null && right == null) {
return true;
}
if (left == null || right == null) {
return false;
}
// UnaryExpression
if (left instanceof UnaryExpression) {
if (right instanceof UnaryExpression) {
UnaryExpression leftArg = (UnaryExpression)left;
UnaryExpression rightArg = (UnaryExpression)right;
return unaryExpressionsEqual(leftArg, rightArg);
}
return false;
}
// BinaryExpression
if (left instanceof BinaryExpression) {
if (right instanceof BinaryExpression) {
BinaryExpression leftArg = (BinaryExpression)left;
BinaryExpression rightArg = (BinaryExpression)right;
return binaryExpressionsEqual(leftArg, rightArg);
}
return false;
}
// TernaryExpression
if (left instanceof TernaryExpression) {
if (right instanceof TernaryExpression) {
TernaryExpression leftArg = (TernaryExpression)left;
TernaryExpression rightArg = (TernaryExpression)right;
return ternaryExpressionsEqual(leftArg, rightArg);
}
return false;
}
// NaryExpression
if (left instanceof NaryExpression) {
if (right instanceof NaryExpression) {
NaryExpression leftArg = (NaryExpression)left;
NaryExpression rightArg = (NaryExpression)right;
return naryExpressionsEqual(leftArg, rightArg);
}
return false;
}
if (!left.getClass().getCanonicalName().equals(right.getClass().getCanonicalName())) {
return false;
}
// Round
if (left instanceof Round) {
if (right instanceof Round) {
Round leftArg = (Round)left;
Round rightArg = (Round)right;
return expressionsEqual(leftArg.getOperand(), rightArg.getOperand())
&& expressionsEqual(leftArg.getPrecision(), rightArg.getPrecision());
}
return false;
}
// Combine
if (left instanceof Combine) {
if (right instanceof Combine) {
Combine leftArg = (Combine)left;
Combine rightArg = (Combine)right;
return expressionsEqual(leftArg.getSource(), rightArg.getSource())
&& expressionsEqual(leftArg.getSeparator(), rightArg.getSeparator());
}
return false;
}
// Split
if (left instanceof Split) {
if (right instanceof Split) {
Split leftArg = (Split)left;
Split rightArg = (Split)right;
return expressionsEqual(leftArg.getStringToSplit(), rightArg.getStringToSplit())
&& expressionsEqual(leftArg.getSeparator(), rightArg.getSeparator());
}
return false;
}
// SplitOnMatches
if (left instanceof SplitOnMatches) {
if (right instanceof SplitOnMatches) {
SplitOnMatches leftArg = (SplitOnMatches)left;
SplitOnMatches rightArg = (SplitOnMatches)right;
return expressionsEqual(leftArg.getStringToSplit(), rightArg.getStringToSplit())
&& expressionsEqual(leftArg.getSeparatorPattern(), rightArg.getSeparatorPattern());
}
return false;
}
// PositionOf
if (left instanceof PositionOf) {
if (right instanceof PositionOf) {
PositionOf leftArg = (PositionOf)left;
PositionOf rightArg = (PositionOf)right;
return expressionsEqual(leftArg.getString(), rightArg.getString())
&& expressionsEqual(leftArg.getPattern(), rightArg.getPattern());
}
return false;
}
// LastPositionOf
if (left instanceof LastPositionOf) {
if (right instanceof LastPositionOf) {
LastPositionOf leftArg = (LastPositionOf)left;
LastPositionOf rightArg = (LastPositionOf)right;
return expressionsEqual(leftArg.getString(), rightArg.getString())
&& expressionsEqual(leftArg.getPattern(), rightArg.getPattern());
}
return false;
}
// Substring
if (left instanceof Substring) {
if (right instanceof Substring) {
Substring leftArg = (Substring)left;
Substring rightArg = (Substring)right;
return expressionsEqual(leftArg.getStringToSub(), rightArg.getStringToSub())
&& expressionsEqual(leftArg.getStartIndex(), rightArg.getStartIndex())
&& expressionsEqual(leftArg.getLength(), rightArg.getLength());
}
return false;
}
// TimeOfDay
// Today
// Now
// Time
if (left instanceof Time) {
if (right instanceof Time) {
Time leftArg = (Time)left;
Time rightArg = (Time)right;
return expressionsEqual(leftArg.getHour(), rightArg.getHour())
&& expressionsEqual(leftArg.getMinute(), rightArg.getMinute())
&& expressionsEqual(leftArg.getSecond(), rightArg.getSecond())
&& expressionsEqual(leftArg.getMillisecond(), rightArg.getMillisecond());
}
return false;
}
// Date
if (left instanceof Date) {
if (right instanceof Date) {
Date leftArg = (Date)left;
Date rightArg = (Date)right;
return expressionsEqual(leftArg.getYear(), rightArg.getYear())
&& expressionsEqual(leftArg.getMonth(), rightArg.getMonth())
&& expressionsEqual(leftArg.getDay(), rightArg.getDay());
}
return false;
}
// DateTime
if (left instanceof DateTime) {
if (right instanceof DateTime) {
DateTime leftArg = (DateTime)left;
DateTime rightArg = (DateTime)right;
return expressionsEqual(leftArg.getYear(), rightArg.getYear())
&& expressionsEqual(leftArg.getMonth(), rightArg.getMonth())
&& expressionsEqual(leftArg.getDay(), rightArg.getDay())
&& expressionsEqual(leftArg.getHour(), rightArg.getHour())
&& expressionsEqual(leftArg.getMinute(), rightArg.getMinute())
&& expressionsEqual(leftArg.getSecond(), rightArg.getSecond())
&& expressionsEqual(leftArg.getMillisecond(), rightArg.getMillisecond())
&& expressionsEqual(leftArg.getTimezoneOffset(), rightArg.getTimezoneOffset());
}
return false;
}
// First
if (left instanceof First) {
if (right instanceof First) {
First leftArg = (First)left;
First rightArg = (First)right;
return expressionsEqual(leftArg.getSource(), rightArg.getSource())
&& stringsEqual(leftArg.getOrderBy(), rightArg.getOrderBy());
}
return false;
}
// Last
if (left instanceof Last) {
if (right instanceof Last) {
Last leftArg = (Last)left;
Last rightArg = (Last)right;
return expressionsEqual(leftArg.getSource(), rightArg.getSource())
&& stringsEqual(leftArg.getOrderBy(), rightArg.getOrderBy());
}
return false;
}
// IndexOf
if (left instanceof IndexOf) {
if (right instanceof IndexOf) {
IndexOf leftArg = (IndexOf)left;
IndexOf rightArg = (IndexOf)right;
return expressionsEqual(leftArg.getSource(), rightArg.getSource())
&& expressionsEqual(leftArg.getElement(), rightArg.getElement());
}
return false;
}
// Slice
if (left instanceof Slice) {
if (right instanceof Slice) {
Slice leftArg = (Slice)left;
Slice rightArg = (Slice)right;
return expressionsEqual(leftArg.getSource(), rightArg.getSource())
&& expressionsEqual(leftArg.getStartIndex(), rightArg.getStartIndex())
&& expressionsEqual(leftArg.getEndIndex(), rightArg.getEndIndex());
}
return false;
}
// Children
if (left instanceof Children) {
if (right instanceof Children) {
Children leftArg = (Children)left;
Children rightArg = (Children)right;
return expressionsEqual(leftArg.getSource(), rightArg.getSource());
}
return false;
}
// Descendents
if (left instanceof Descendents) {
if (right instanceof Descendents) {
Descendents leftArg = (Descendents)left;
Descendents rightArg = (Descendents)right;
return expressionsEqual(leftArg.getSource(), rightArg.getSource());
}
return false;
}
// Message
if (left instanceof Message) {
if (right instanceof Message) {
Message leftArg = (Message)left;
Message rightArg = (Message)right;
return expressionsEqual(leftArg.getSource(), rightArg.getSource())
&& expressionsEqual(leftArg.getCode(), rightArg.getCode())
&& expressionsEqual(leftArg.getCondition(), rightArg.getCondition())
&& expressionsEqual(leftArg.getMessage(), rightArg.getMessage())
&& expressionsEqual(leftArg.getSeverity(), rightArg.getSeverity());
}
return false;
}
// Generally speaking we would return false here, but because we've covered all the cases, we return true
return true;
}
public boolean operandsEqual(UnaryExpression left, UnaryExpression right) {
return expressionsEqual(left.getOperand(), right.getOperand());
}
public boolean unaryExpressionsEqual(UnaryExpression left, UnaryExpression right) {
if (left == null && right == null) {
return true;
}
if (left == null || right == null) {
return false;
}
if (!left.getClass().getCanonicalName().equals(right.getClass().getCanonicalName())) {
return false;
}
if (!operandsEqual(left, right)) {
return false;
}
// Abs
// As
if (left instanceof As) {
if (right instanceof As) {
As leftArg = (As)left;
As rightArg = (As)right;
return qnamesEqual(leftArg.getAsType(), rightArg.getAsType())
&& typeSpecifiersEqual(leftArg.getAsTypeSpecifier(), rightArg.getAsTypeSpecifier())
&& leftArg.isStrict() == rightArg.isStrict();
}
}
// Ceiling
// CanConvert
if (left instanceof CanConvert) {
if (right instanceof CanConvert) {
CanConvert leftArg = (CanConvert)left;
CanConvert rightArg = (CanConvert) right;
return qnamesEqual(leftArg.getToType(), rightArg.getToType())
&& typeSpecifiersEqual(leftArg.getToTypeSpecifier(), rightArg.getToTypeSpecifier());
}
return false;
}
// Convert
if (left instanceof Convert) {
if (right instanceof Convert) {
Convert leftArg = (Convert)left;
Convert rightArg = (Convert) right;
return qnamesEqual(leftArg.getToType(), rightArg.getToType())
&& typeSpecifiersEqual(leftArg.getToTypeSpecifier(), rightArg.getToTypeSpecifier());
}
return false;
}
// ConvertsToBoolean
// ConvertsToDate
// ConvertsToDateTime
// ConvertsToDecimal
// ConvertsToInteger
// ConvertsToLong
// ConvertsToQuantity
// ConvertsToRatio
// ConvertsToString
// ConvertsToTime
// DateFrom
// DateTimeComponentFrom
if (left instanceof DateTimeComponentFrom) {
if (right instanceof DateTimeComponentFrom) {
DateTimeComponentFrom leftArg = (DateTimeComponentFrom)left;
DateTimeComponentFrom rightArg = (DateTimeComponentFrom)right;
return leftArg.getPrecision() == rightArg.getPrecision();
}
return false;
}
// Distinct
// End
// Exists
// Exp
// Flatten
// Floor
// Is
if (left instanceof Is) {
if (right instanceof Is) {
Is leftArg = (Is)left;
Is rightArg = (Is)right;
return qnamesEqual(leftArg.getIsType(), rightArg.getIsType())
&& typeSpecifiersEqual(leftArg.getIsTypeSpecifier(), rightArg.getIsTypeSpecifier());
}
return false;
}
// IsFalse
// IsNull
// IsTrue
// Length
// Ln
// Lower
// Negate
// Not
// PointFrom
// Precision
// Predecessor
// SingletonFrom
// Size
// Start
// Successor
// TimeFrom
// TimezoneFrom
// TimezoneOffsetFrom
// ToBoolean
// ToConcept
// ToChars
// ToDate
// ToDateTime
// ToDecimal
// ToInteger
// ToLong
// ToList
// ToQuantity
// ToRatio
// ToString
// ToTime
// Truncate
// Upper
// Width
// We've covered all the special cases above, so if we make it here, the expressions are equal
return true;
}
public boolean binaryExpressionsEqual(BinaryExpression left, BinaryExpression right) {
if (left == null && right == null) {
return true;
}
if (left == null || right == null) {
return false;
}
if (!left.getClass().getCanonicalName().equals(right.getClass().getCanonicalName())) {
return false;
}
if (!operandsEqual(left, right)) {
return false;
}
// TODO: Handle special cases for operators that have a precision modifier
// Add
// After
// And
// Before
// CanConvertQuantity
// Contains
// ConvertQuantity
// Collapse
// DifferenceBetween
// Divide
// DurationBetween
// Ends
// EndsWith
// Equal
// Equivalent
// Expand
// Greater
// GreaterOrEqual
// HighBoundary
// Implies
// In
// IncludedIn
// Includes
// Indexer
// Less
// LessOrEqual
// Log
// LowBoundary
// Matches
// Meets
// MeetsAfter
// MeetsBefore
// Modulo
// Multiply
// NotEqual
// Or
// Overlaps
// OverlapsAfter
// OverlapsBefore
// Power
// ProperContains
// ProperIn
// ProperIncludedIn
// ProperIncludes
// SameAs
// SameOrAfter
// SameOrBefore
// Starts
// StartsWith
// Subtract
// Times
// TruncatedDivide
// Xor
return true;
}
public boolean ternaryExpressionsEqual(TernaryExpression left, TernaryExpression right) {
if (left == null && right == null) {
return true;
}
if (left == null || right == null) {
return false;
}
if (!left.getClass().getCanonicalName().equals(right.getClass().getCanonicalName())) {
return false;
}
if (!operandsEqual(left, right)) {
return false;
}
// ReplaceMatches
return true;
}
public boolean naryExpressionsEqual(NaryExpression left, NaryExpression right) {
if (left == null && right == null) {
return true;
}
if (left == null || right == null) {
return false;
}
if (!left.getClass().getCanonicalName().equals(right.getClass().getCanonicalName())) {
return false;
}
if (!operandsEqual(left, right)) {
return false;
}
// Coalesce
// Concatenate
// Except
// Intersect
// Union
return false;
}
public boolean aggregateExpressionsEqual(AggregateExpression left, AggregateExpression right) {
if (left == null && right == null) {
return true;
}
if (left == null || right == null) {
return false;
}
if (!left.getClass().getCanonicalName().equals(right.getClass().getCanonicalName())) {
return false;
}
if (!expressionsEqual(left.getSource(), right.getSource()) || !stringsEqual(left.getPath(), right.getPath())) {
return false;
}
// Aggregate
if (left instanceof Aggregate) {
if (right instanceof Aggregate) {
Aggregate leftArg = (Aggregate)left;
Aggregate rightArg = (Aggregate)right;
return expressionsEqual(leftArg.getInitialValue(), rightArg.getInitialValue())
&& expressionsEqual(leftArg.getIteration(), rightArg.getIteration());
}
}
// Count
// Sum
// Product
// Min
// Max
// Avg
// GeometricMean
// Median
// Mode
// Variance
// StdDev
// PopulationVariance
// PopulationStdDev
// AllTrue
// AnyTrue
return true;
}
}