use of org.hl7.fhir.r5.model.Expression in project clinical_quality_language by cqframework.
the class Cql2ElmVisitor method visitWithinIntervalOperatorPhrase.
@Override
public Object visitWithinIntervalOperatorPhrase(cqlParser.WithinIntervalOperatorPhraseContext ctx) {
// ('starts' | 'ends' | 'occurs')? 'properly'? 'within' quantityLiteral 'of' ('start' | 'end')?
// A starts within 3 days of start B
// * start of A in [start of B - 3 days, start of B + 3 days] and start B is not null
// A starts within 3 days of B
// * start of A in [start of B - 3 days, end of B + 3 days]
TimingOperatorContext timingOperator = timingOperators.peek();
boolean isProper = false;
for (ParseTree child : ctx.children) {
if ("starts".equals(child.getText())) {
Start start = of.createStart().withOperand(timingOperator.getLeft());
track(start, child);
libraryBuilder.resolveUnaryCall("System", "Start", start);
timingOperator.setLeft(start);
continue;
}
if ("ends".equals(child.getText())) {
End end = of.createEnd().withOperand(timingOperator.getLeft());
track(end, child);
libraryBuilder.resolveUnaryCall("System", "End", end);
timingOperator.setLeft(end);
continue;
}
if ("start".equals(child.getText())) {
Start start = of.createStart().withOperand(timingOperator.getRight());
track(start, child);
libraryBuilder.resolveUnaryCall("System", "Start", start);
timingOperator.setRight(start);
continue;
}
if ("end".equals(child.getText())) {
End end = of.createEnd().withOperand(timingOperator.getRight());
track(end, child);
libraryBuilder.resolveUnaryCall("System", "End", end);
timingOperator.setRight(end);
continue;
}
if ("properly".equals(child.getText())) {
isProper = true;
continue;
}
}
Quantity quantity = (Quantity) visit(ctx.quantity());
Expression lowerBound = null;
Expression upperBound = null;
Expression initialBound = null;
if (timingOperator.getRight().getResultType() instanceof IntervalType) {
lowerBound = of.createStart().withOperand(timingOperator.getRight());
track(lowerBound, ctx.quantity());
libraryBuilder.resolveUnaryCall("System", "Start", (Start) lowerBound);
upperBound = of.createEnd().withOperand(timingOperator.getRight());
track(upperBound, ctx.quantity());
libraryBuilder.resolveUnaryCall("System", "End", (End) upperBound);
} else {
lowerBound = timingOperator.getRight();
upperBound = timingOperator.getRight();
initialBound = lowerBound;
}
lowerBound = of.createSubtract().withOperand(lowerBound, quantity);
track(lowerBound, ctx.quantity());
libraryBuilder.resolveBinaryCall("System", "Subtract", (BinaryExpression) lowerBound);
upperBound = of.createAdd().withOperand(upperBound, quantity);
track(upperBound, ctx.quantity());
libraryBuilder.resolveBinaryCall("System", "Add", (BinaryExpression) upperBound);
Interval interval = libraryBuilder.createInterval(lowerBound, !isProper, upperBound, !isProper);
track(interval, ctx.quantity());
In in = of.createIn().withOperand(timingOperator.getLeft(), interval);
libraryBuilder.resolveBinaryCall("System", "In", in);
// if the within is not proper and the interval is being constructed from a single point, add a null check for that point to ensure correct interpretation
if (!isProper && (initialBound != null)) {
IsNull nullTest = of.createIsNull().withOperand(initialBound);
track(nullTest, ctx.quantity());
libraryBuilder.resolveUnaryCall("System", "IsNull", nullTest);
Not notNullTest = of.createNot().withOperand(nullTest);
track(notNullTest, ctx.quantity());
libraryBuilder.resolveUnaryCall("System", "Not", notNullTest);
And and = of.createAnd().withOperand(in, notNullTest);
track(and, ctx.quantity());
libraryBuilder.resolveBinaryCall("System", "And", and);
return and;
}
// Otherwise, return the constructed in
return in;
}
use of org.hl7.fhir.r5.model.Expression in project clinical_quality_language by cqframework.
the class Cql2ElmVisitor method visitBeforeOrAfterIntervalOperatorPhrase.
@Override
public Object visitBeforeOrAfterIntervalOperatorPhrase(cqlParser.BeforeOrAfterIntervalOperatorPhraseContext ctx) {
// ('starts' | 'ends' | 'occurs')? quantityOffset? ('before' | 'after') dateTimePrecisionSpecifier? ('start' | 'end')?
// duration before/after
// A starts 3 days before start B
// * start of A same day as start of B - 3 days
// A starts 3 days after start B
// * start of A same day as start of B + 3 days
// or more/less duration before/after
// A starts 3 days or more before start B
// * start of A <= start of B - 3 days
// A starts 3 days or more after start B
// * start of A >= start of B + 3 days
// A starts 3 days or less before start B
// * start of A in [start of B - 3 days, start of B) and B is not null
// A starts 3 days or less after start B
// * start of A in (start of B, start of B + 3 days] and B is not null
// less/more than duration before/after
// A starts more than 3 days before start B
// * start of A < start of B - 3 days
// A starts more than 3 days after start B
// * start of A > start of B + 3 days
// A starts less than 3 days before start B
// * start of A in (start of B - 3 days, start of B)
// A starts less than 3 days after start B
// * start of A in (start of B, start of B + 3 days)
TimingOperatorContext timingOperator = timingOperators.peek();
boolean isBefore = false;
boolean isInclusive = false;
for (ParseTree child : ctx.children) {
if ("starts".equals(child.getText())) {
Start start = of.createStart().withOperand(timingOperator.getLeft());
track(start, child);
libraryBuilder.resolveUnaryCall("System", "Start", start);
timingOperator.setLeft(start);
continue;
}
if ("ends".equals(child.getText())) {
End end = of.createEnd().withOperand(timingOperator.getLeft());
track(end, child);
libraryBuilder.resolveUnaryCall("System", "End", end);
timingOperator.setLeft(end);
continue;
}
if ("start".equals(child.getText())) {
Start start = of.createStart().withOperand(timingOperator.getRight());
track(start, child);
libraryBuilder.resolveUnaryCall("System", "Start", start);
timingOperator.setRight(start);
continue;
}
if ("end".equals(child.getText())) {
End end = of.createEnd().withOperand(timingOperator.getRight());
track(end, child);
libraryBuilder.resolveUnaryCall("System", "End", end);
timingOperator.setRight(end);
continue;
}
}
for (ParseTree child : ctx.temporalRelationship().children) {
if ("before".equals(child.getText())) {
isBefore = true;
continue;
}
if ("on or".equals(child.getText()) || "or on".equals(child.getText())) {
isInclusive = true;
continue;
}
}
String dateTimePrecision = ctx.dateTimePrecisionSpecifier() != null ? ctx.dateTimePrecisionSpecifier().dateTimePrecision().getText() : null;
if (ctx.quantityOffset() == null) {
if (isInclusive) {
if (isBefore) {
SameOrBefore sameOrBefore = of.createSameOrBefore().withOperand(timingOperator.getLeft(), timingOperator.getRight());
if (dateTimePrecision != null) {
sameOrBefore.setPrecision(parseComparableDateTimePrecision(dateTimePrecision));
}
libraryBuilder.resolveBinaryCall("System", "SameOrBefore", sameOrBefore, true, true);
return sameOrBefore;
} else {
SameOrAfter sameOrAfter = of.createSameOrAfter().withOperand(timingOperator.getLeft(), timingOperator.getRight());
if (dateTimePrecision != null) {
sameOrAfter.setPrecision(parseComparableDateTimePrecision(dateTimePrecision));
}
libraryBuilder.resolveBinaryCall("System", "SameOrAfter", sameOrAfter, true, true);
return sameOrAfter;
}
} else {
if (isBefore) {
Before before = of.createBefore().withOperand(timingOperator.getLeft(), timingOperator.getRight());
if (dateTimePrecision != null) {
before.setPrecision(parseComparableDateTimePrecision(dateTimePrecision));
}
libraryBuilder.resolveBinaryCall("System", "Before", before, true, true);
return before;
} else {
After after = of.createAfter().withOperand(timingOperator.getLeft(), timingOperator.getRight());
if (dateTimePrecision != null) {
after.setPrecision(parseComparableDateTimePrecision(dateTimePrecision));
}
libraryBuilder.resolveBinaryCall("System", "After", after, true, true);
return after;
}
}
} else {
Quantity quantity = (Quantity) visit(ctx.quantityOffset().quantity());
if (timingOperator.getLeft().getResultType() instanceof IntervalType) {
if (isBefore) {
End end = of.createEnd().withOperand(timingOperator.getLeft());
track(end, timingOperator.getLeft());
libraryBuilder.resolveUnaryCall("System", "End", end);
timingOperator.setLeft(end);
} else {
Start start = of.createStart().withOperand(timingOperator.getLeft());
track(start, timingOperator.getLeft());
libraryBuilder.resolveUnaryCall("System", "Start", start);
timingOperator.setLeft(start);
}
}
if (timingOperator.getRight().getResultType() instanceof IntervalType) {
if (isBefore) {
Start start = of.createStart().withOperand(timingOperator.getRight());
track(start, timingOperator.getRight());
libraryBuilder.resolveUnaryCall("System", "Start", start);
timingOperator.setRight(start);
} else {
End end = of.createEnd().withOperand(timingOperator.getRight());
track(end, timingOperator.getRight());
libraryBuilder.resolveUnaryCall("System", "End", end);
timingOperator.setRight(end);
}
}
if (ctx.quantityOffset().offsetRelativeQualifier() == null && ctx.quantityOffset().exclusiveRelativeQualifier() == null) {
// For an After, add the quantity to the right operand
if (isBefore) {
Subtract subtract = of.createSubtract().withOperand(timingOperator.getRight(), quantity);
track(subtract, timingOperator.getRight());
libraryBuilder.resolveBinaryCall("System", "Subtract", subtract);
timingOperator.setRight(subtract);
} else {
Add add = of.createAdd().withOperand(timingOperator.getRight(), quantity);
track(add, timingOperator.getRight());
libraryBuilder.resolveBinaryCall("System", "Add", add);
timingOperator.setRight(add);
}
SameAs sameAs = of.createSameAs().withOperand(timingOperator.getLeft(), timingOperator.getRight());
if (dateTimePrecision != null) {
sameAs.setPrecision(parseComparableDateTimePrecision(dateTimePrecision));
}
libraryBuilder.resolveBinaryCall("System", "SameAs", sameAs);
return sameAs;
} else {
boolean isOffsetInclusive = ctx.quantityOffset().offsetRelativeQualifier() != null;
String qualifier = ctx.quantityOffset().offsetRelativeQualifier() != null ? ctx.quantityOffset().offsetRelativeQualifier().getText() : ctx.quantityOffset().exclusiveRelativeQualifier().getText();
switch(qualifier) {
case "more than":
case "or more":
// For an After, add the quantity to the right operand
if (isBefore) {
Subtract subtract = of.createSubtract().withOperand(timingOperator.getRight(), quantity);
track(subtract, timingOperator.getRight());
libraryBuilder.resolveBinaryCall("System", "Subtract", subtract);
timingOperator.setRight(subtract);
if (!isOffsetInclusive) {
Before before = of.createBefore().withOperand(timingOperator.getLeft(), timingOperator.getRight());
if (dateTimePrecision != null) {
before.setPrecision(parseComparableDateTimePrecision(dateTimePrecision));
}
libraryBuilder.resolveBinaryCall("System", "Before", before, true, true);
return before;
} else {
SameOrBefore sameOrBefore = of.createSameOrBefore().withOperand(timingOperator.getLeft(), timingOperator.getRight());
if (dateTimePrecision != null) {
sameOrBefore.setPrecision(parseComparableDateTimePrecision(dateTimePrecision));
}
libraryBuilder.resolveBinaryCall("System", "SameOrBefore", sameOrBefore, true, true);
return sameOrBefore;
}
} else {
Add add = of.createAdd().withOperand(timingOperator.getRight(), quantity);
track(add, timingOperator.getRight());
libraryBuilder.resolveBinaryCall("System", "Add", add);
timingOperator.setRight(add);
if (!isOffsetInclusive) {
After after = of.createAfter().withOperand(timingOperator.getLeft(), timingOperator.getRight());
if (dateTimePrecision != null) {
after.setPrecision(parseComparableDateTimePrecision(dateTimePrecision));
}
libraryBuilder.resolveBinaryCall("System", "After", after, true, true);
return after;
} else {
SameOrAfter sameOrAfter = of.createSameOrAfter().withOperand(timingOperator.getLeft(), timingOperator.getRight());
if (dateTimePrecision != null) {
sameOrAfter.setPrecision(parseComparableDateTimePrecision(dateTimePrecision));
}
libraryBuilder.resolveBinaryCall("System", "SameOrAfter", sameOrAfter, true, true);
return sameOrAfter;
}
}
case "less than":
case "or less":
// For Less Than/Or Less, Use an In
// For Before, construct an interval from right - quantity to right
// For After, construct an interval from right to right + quantity
Expression lowerBound = null;
Expression upperBound = null;
Expression right = timingOperator.getRight();
if (isBefore) {
lowerBound = of.createSubtract().withOperand(right, quantity);
track(lowerBound, right);
libraryBuilder.resolveBinaryCall("System", "Subtract", (BinaryExpression) lowerBound);
upperBound = right;
} else {
lowerBound = right;
upperBound = of.createAdd().withOperand(right, quantity);
track(upperBound, right);
libraryBuilder.resolveBinaryCall("System", "Add", (BinaryExpression) upperBound);
}
// 3 days or less before -> [B - 3 days, B)
// less than 3 days before -> (B - 3 days, B)
// 3 days or less after -> (B, B + 3 days]
// less than 3 days after -> (B, B + 3 days)
Interval interval = isBefore ? libraryBuilder.createInterval(lowerBound, isOffsetInclusive, upperBound, isInclusive) : libraryBuilder.createInterval(lowerBound, isInclusive, upperBound, isOffsetInclusive);
track(interval, ctx.quantityOffset());
In in = of.createIn().withOperand(timingOperator.getLeft(), interval);
if (dateTimePrecision != null) {
in.setPrecision(parseComparableDateTimePrecision(dateTimePrecision));
}
track(in, ctx.quantityOffset());
libraryBuilder.resolveBinaryCall("System", "In", in);
// if the offset or comparison is inclusive, add a null check for B to ensure correct interpretation
if (isOffsetInclusive || isInclusive) {
IsNull nullTest = of.createIsNull().withOperand(right);
track(nullTest, ctx.quantityOffset());
libraryBuilder.resolveUnaryCall("System", "IsNull", nullTest);
Not notNullTest = of.createNot().withOperand(nullTest);
track(notNullTest, ctx.quantityOffset());
libraryBuilder.resolveUnaryCall("System", "Not", notNullTest);
And and = of.createAnd().withOperand(in, notNullTest);
track(and, ctx.quantityOffset());
libraryBuilder.resolveBinaryCall("System", "And", and);
return and;
}
// Otherwise, return the constructed in
return in;
}
}
}
throw new IllegalArgumentException("Unable to resolve interval operator phrase.");
}
use of org.hl7.fhir.r5.model.Expression in project clinical_quality_language by cqframework.
the class PositionOfInvocation method setOperands.
@Override
public void setOperands(Iterable<Expression> operands) {
Iterator<Expression> it = operands.iterator();
if (!it.hasNext()) {
throw new IllegalArgumentException("PositionOf operation requires two operands.");
}
PositionOf pos = (PositionOf) expression;
pos.setPattern(it.next());
if (!it.hasNext()) {
throw new IllegalArgumentException("PositionOf operation requires two operands.");
}
pos.setString(it.next());
}
use of org.hl7.fhir.r5.model.Expression in project clinical_quality_language by cqframework.
the class RoundInvocation method setOperands.
@Override
public void setOperands(Iterable<Expression> operands) {
Iterator<Expression> it = operands.iterator();
if (!it.hasNext()) {
throw new IllegalArgumentException("Round operation requires one or two operands.");
}
Round round = (Round) expression;
round.setOperand(it.next());
if (it.hasNext()) {
round.setPrecision(it.next());
}
}
use of org.hl7.fhir.r5.model.Expression in project clinical_quality_language by cqframework.
the class SkipInvocation method setOperands.
@Override
public void setOperands(Iterable<Expression> operands) {
boolean first = true;
for (Expression operand : operands) {
if (first) {
((Slice) expression).setSource(operand);
first = false;
} else {
((Slice) expression).setStartIndex(operand);
}
}
}
Aggregations