All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.cqframework.cql.cql2elm.SystemFunctionResolver Maven / Gradle / Ivy

Go to download

The cql-to-elm library for the Clinical Quality Language Java reference implementation

There is a newer version: 3.18.0
Show newest version
package org.cqframework.cql.cql2elm;

import java.util.ArrayList;
import java.util.List;
import org.cqframework.cql.cql2elm.model.Conversion;
import org.cqframework.cql.cql2elm.model.Invocation;
import org.cqframework.cql.cql2elm.model.PropertyResolution;
import org.cqframework.cql.cql2elm.model.SystemModel;
import org.cqframework.cql.cql2elm.model.invocation.*;
import org.cqframework.cql.elm.IdObjectFactory;
import org.hl7.elm.r1.*;

public class SystemFunctionResolver {
    private final IdObjectFactory of;
    private final LibraryBuilder builder;

    public SystemFunctionResolver(LibraryBuilder builder, IdObjectFactory of) {
        this.builder = builder;
        this.of = builder.getObjectFactory();
    }

    public Invocation resolveSystemFunction(FunctionRef fun) {
        if (fun.getLibraryName() == null || "System".equals(fun.getLibraryName())) {
            switch (fun.getName()) {
                    // Aggregate Functions
                case "AllTrue":
                case "AnyTrue":
                case "Avg":
                case "Count":
                case "GeometricMean":
                case "Max":
                case "Median":
                case "Min":
                case "Mode":
                case "PopulationStdDev":
                case "PopulationVariance":
                case "Product":
                case "StdDev":
                case "Sum":
                case "Variance": {
                    return resolveAggregate(fun);
                }

                    // Arithmetic Functions
                case "Abs":
                case "Ceiling":
                case "Exp":
                case "Floor":
                case "Ln":
                case "Negate":
                case "Precision":
                case "Predecessor":
                case "Successor":
                case "Truncate": {
                    return resolveUnary(fun);
                }

                case "HighBoundary":
                case "Log":
                case "LowBoundary":
                case "Modulo":
                case "Power":
                case "TruncatedDivide": {
                    return resolveBinary(fun);
                }

                case "Round": {
                    return resolveRound(fun);
                }

                    // Clinical Functions
                case "AgeInYears":
                case "AgeInMonths": {
                    checkNumberOfOperands(fun, 0);
                    return resolveCalculateAge(
                            builder.enforceCompatible(
                                    getPatientBirthDateProperty(), builder.resolveTypeName("System", "Date")),
                            resolveAgeRelatedFunctionPrecision(fun));
                }

                case "AgeInWeeks":
                case "AgeInDays":
                case "AgeInHours":
                case "AgeInMinutes":
                case "AgeInSeconds":
                case "AgeInMilliseconds": {
                    checkNumberOfOperands(fun, 0);
                    return resolveCalculateAge(
                            builder.ensureCompatible(
                                    getPatientBirthDateProperty(), builder.resolveTypeName("System", "DateTime")),
                            resolveAgeRelatedFunctionPrecision(fun));
                }

                case "AgeInYearsAt":
                case "AgeInMonthsAt":
                case "AgeInWeeksAt":
                case "AgeInDaysAt": {
                    checkNumberOfOperands(fun, 1);
                    List ops = new ArrayList<>();
                    Expression op = fun.getOperand().get(0);
                    // If the op is not a Date or DateTime, attempt to get it to convert it to a Date or DateTime
                    // If the op can be converted to both a Date and a DateTime, throw an ambiguous error
                    if (!(op.getResultType().isSubTypeOf(builder.resolveTypeName("System", "Date"))
                            || op.getResultType().isSubTypeOf(builder.resolveTypeName("System", "DateTime")))) {
                        Conversion dateConversion = builder.findConversion(
                                op.getResultType(), builder.resolveTypeName("System", "Date"), true, false);
                        Conversion dateTimeConversion = builder.findConversion(
                                op.getResultType(), builder.resolveTypeName("System", "DateTime"), true, false);
                        if (dateConversion != null && dateTimeConversion != null) {
                            if (dateConversion.getScore() == dateTimeConversion.getScore()) {
                                // ERROR
                                throw new IllegalArgumentException(String.format(
                                        "Ambiguous implicit conversion from %s to %s or %s.",
                                        op.getResultType().toString(),
                                        dateConversion.getToType().toString(),
                                        dateTimeConversion.getToType().toString()));
                            } else if (dateConversion.getScore() < dateTimeConversion.getScore()) {
                                op = builder.convertExpression(op, dateConversion);
                            } else {
                                op = builder.convertExpression(op, dateTimeConversion);
                            }
                        } else if (dateConversion != null) {
                            op = builder.convertExpression(op, dateConversion);
                        } else if (dateTimeConversion != null) {
                            op = builder.convertExpression(op, dateTimeConversion);
                        } else {
                            // ERROR
                            throw new IllegalArgumentException(String.format(
                                    "Could not resolve call to operator %s with argument of type %s.",
                                    fun.getName(), op.getResultType().toString()));
                        }
                    }
                    ops.add(builder.enforceCompatible(getPatientBirthDateProperty(), op.getResultType()));
                    ops.add(op);
                    return resolveCalculateAgeAt(ops, resolveAgeRelatedFunctionPrecision(fun));
                }

                case "AgeInHoursAt":
                case "AgeInMinutesAt":
                case "AgeInSecondsAt":
                case "AgeInMillisecondsAt": {
                    List ops = new ArrayList<>();
                    ops.add(getPatientBirthDateProperty());
                    ops.addAll(fun.getOperand());
                    return resolveCalculateAgeAt(ops, resolveAgeRelatedFunctionPrecision(fun));
                }

                case "CalculateAgeInYears":
                case "CalculateAgeInMonths":
                case "CalculateAgeInWeeks":
                case "CalculateAgeInDays":
                case "CalculateAgeInHours":
                case "CalculateAgeInMinutes":
                case "CalculateAgeInSeconds":
                case "CalculateAgeInMilliseconds": {
                    checkNumberOfOperands(fun, 1);
                    return resolveCalculateAge(fun.getOperand().get(0), resolveAgeRelatedFunctionPrecision(fun));
                }

                case "CalculateAgeInYearsAt":
                case "CalculateAgeInMonthsAt":
                case "CalculateAgeInWeeksAt":
                case "CalculateAgeInDaysAt":
                case "CalculateAgeInHoursAt":
                case "CalculateAgeInMinutesAt":
                case "CalculateAgeInSecondsAt":
                case "CalculateAgeInMillisecondsAt": {
                    return resolveCalculateAgeAt(fun.getOperand(), resolveAgeRelatedFunctionPrecision(fun));
                }

                    // DateTime Functions
                case "DateTime": {
                    return resolveDateTime(fun);
                }

                case "Date": {
                    return resolveDate(fun);
                }

                case "Time": {
                    return resolveTime(fun);
                }

                case "Now":
                case "now": {
                    return resolveNow(fun);
                }

                case "Today":
                case "today": {
                    return resolveToday(fun);
                }

                case "TimeOfDay":
                case "timeOfDay": {
                    return resolveTimeOfDay(fun);
                }

                    // List Functions
                case "IndexOf": {
                    return resolveIndexOf(fun);
                }

                case "First": {
                    return resolveFirst(fun);
                }

                case "Last": {
                    return resolveLast(fun);
                }

                case "Skip": {
                    return resolveSkip(fun);
                }

                case "Take": {
                    return resolveTake(fun);
                }

                case "Tail": {
                    return resolveTail(fun);
                }

                case "Contains":
                case "Expand":
                case "In":
                case "Includes":
                case "IncludedIn":
                case "ProperIncludes":
                case "ProperIncludedIn": {
                    return resolveBinary(fun);
                }

                case "Distinct":
                case "Exists":
                case "Flatten":
                case "Collapse":
                case "SingletonFrom":
                case "ExpandValueSet": {
                    return resolveUnary(fun);
                }

                case "Coalesce":
                case "Intersect":
                case "Union":
                case "Except": {
                    return resolveNary(fun);
                }

                case "IsNull":
                case "IsTrue":
                case "IsFalse": {
                    return resolveUnary(fun);
                }

                    // Overloaded Functions
                case "Length":
                case "Width":
                case "Size": {
                    return resolveUnary(fun);
                }

                    // String Functions
                case "Indexer":
                case "StartsWith":
                case "EndsWith":
                case "Matches": {
                    return resolveBinary(fun);
                }

                case "ReplaceMatches": {
                    return resolveTernary(fun);
                }

                case "Concatenate": {
                    return resolveNary(fun);
                }

                case "Combine": {
                    return resolveCombine(fun);
                }

                case "Split": {
                    return resolveSplit(fun);
                }

                case "SplitOnMatches": {
                    return resolveSplitOnMatches(fun);
                }

                case "Upper":
                case "Lower": {
                    return resolveUnary(fun);
                }

                case "PositionOf": {
                    return resolvePositionOf(fun);
                }

                case "LastPositionOf": {
                    return resolveLastPositionOf(fun);
                }

                case "Substring": {
                    return resolveSubstring(fun);
                }

                    // Logical Functions
                case "Not": {
                    return resolveUnary(fun);
                }

                case "And":
                case "Or":
                case "Xor":
                case "Implies": {
                    return resolveBinary(fun);
                }

                    // Type Functions
                case "ConvertsToString":
                case "ConvertsToBoolean":
                case "ConvertsToInteger":
                case "ConvertsToLong":
                case "ConvertsToDecimal":
                case "ConvertsToDateTime":
                case "ConvertsToDate":
                case "ConvertsToTime":
                case "ConvertsToQuantity":
                case "ConvertsToRatio":
                case "ToString":
                case "ToBoolean":
                case "ToInteger":
                case "ToLong":
                case "ToDecimal":
                case "ToDateTime":
                case "ToDate":
                case "ToTime":
                case "ToQuantity":
                case "ToRatio":
                case "ToConcept":
                case "ToChars": {
                    return resolveUnary(fun);
                }

                    // Quantity Conversion
                case "CanConvertQuantity":
                case "ConvertQuantity": {
                    return resolveBinary(fun);
                }

                    // Comparison Functions
                case "Equal":
                case "NotEqual":
                case "Greater":
                case "GreaterOrEqual":
                case "Less":
                case "LessOrEqual":
                case "Equivalent": {
                    return resolveBinary(fun);
                }

                    // Error Functions
                case "Message":
                    return resolveMessage(fun);
            }
        }

        return null;
    }

    // Age-Related Function Support

    private UnaryExpressionInvocation resolveCalculateAge(Expression e, DateTimePrecision p) {
        CalculateAge operator = of.createCalculateAge().withPrecision(p).withOperand(e);

        UnaryExpressionInvocation invocation = new UnaryExpressionInvocation(operator);
        builder.resolveInvocation("System", "CalculateAge", invocation);
        return invocation;
    }

    private BinaryExpressionInvocation resolveCalculateAgeAt(List e, DateTimePrecision p) {
        CalculateAgeAt operator = of.createCalculateAgeAt().withPrecision(p).withOperand(e);

        BinaryExpressionInvocation invocation = new BinaryExpressionInvocation(operator);
        builder.resolveInvocation("System", "CalculateAgeAt", invocation);
        return invocation;
    }

    private static DateTimePrecision resolveAgeRelatedFunctionPrecision(FunctionRef fun) {
        String name = fun.getName();
        if (name.contains("Years")) {
            return DateTimePrecision.YEAR;
        } else if (name.contains("Months")) {
            return DateTimePrecision.MONTH;
        } else if (name.contains("Weeks")) {
            return DateTimePrecision.WEEK;
        } else if (name.contains("Days")) {
            return DateTimePrecision.DAY;
        } else if (name.contains("Hours")) {
            return DateTimePrecision.HOUR;
        } else if (name.contains("Minutes")) {
            return DateTimePrecision.MINUTE;
        } else if (name.contains("Second")) {
            return DateTimePrecision.SECOND;
        } else if (name.contains("Milliseconds")) {
            return DateTimePrecision.MILLISECOND;
        }

        throw new IllegalArgumentException(String.format("Unknown precision '%s'.", name));
    }

    private Expression getPatientBirthDateProperty() {
        Expression source = builder.resolveIdentifier("Patient", true);
        String birthDateProperty = builder.getDefaultModel().getModelInfo().getPatientBirthDatePropertyName();
        // If the property has a qualifier, resolve it as a path (without model mapping)
        if (birthDateProperty.indexOf('.') >= 1) {
            Property property = of.createProperty().withSource(source).withPath(birthDateProperty);
            property.setResultType(builder.resolvePath(source.getResultType(), property.getPath()));
            return property;
        } else {
            PropertyResolution resolution = builder.resolveProperty(source.getResultType(), birthDateProperty);
            Expression result =
                    builder.buildProperty(source, resolution.getName(), resolution.isSearch(), resolution.getType());
            result = builder.applyTargetMap(result, resolution.getTargetMap());
            return result;
        }
    }

    // Arithmetic Function Support

    private RoundInvocation resolveRound(FunctionRef fun) {
        if (fun.getOperand().isEmpty() || fun.getOperand().size() > 2) {
            throw new IllegalArgumentException(
                    "Could not resolve call to system operator Round.  Expected 1 or 2 arguments.");
        }
        final Round round = of.createRound().withOperand(fun.getOperand().get(0));
        if (fun.getOperand().size() == 2) {
            round.setPrecision(fun.getOperand().get(1));
        }
        RoundInvocation invocation = new RoundInvocation(round);
        builder.resolveInvocation("System", "Round", new RoundInvocation(round));
        return invocation;
    }

    // DateTime Function Support

    private DateTimeInvocation resolveDateTime(FunctionRef fun) {
        final DateTime dt = of.createDateTime();
        DateTimeInvocation.setDateTimeFieldsFromOperands(dt, fun.getOperand());
        DateTimeInvocation invocation = new DateTimeInvocation(dt);
        builder.resolveInvocation("System", "DateTime", invocation);
        return invocation;
    }

    private DateInvocation resolveDate(FunctionRef fun) {
        final Date d = of.createDate();
        DateInvocation.setDateFieldsFromOperands(d, fun.getOperand());
        DateInvocation invocation = new DateInvocation(d);
        builder.resolveInvocation("System", "Date", invocation);
        return invocation;
    }

    private TimeInvocation resolveTime(FunctionRef fun) {
        final Time t = of.createTime();
        TimeInvocation.setTimeFieldsFromOperands(t, fun.getOperand());
        TimeInvocation invocation = new TimeInvocation(t);
        builder.resolveInvocation("System", "Time", invocation);
        return invocation;
    }

    private ZeroOperandExpressionInvocation resolveNow(FunctionRef fun) {
        checkNumberOfOperands(fun, 0);
        final Now now = of.createNow();
        ZeroOperandExpressionInvocation invocation = new ZeroOperandExpressionInvocation(now);
        builder.resolveInvocation("System", "Now", invocation);
        return invocation;
    }

    private ZeroOperandExpressionInvocation resolveToday(FunctionRef fun) {
        checkNumberOfOperands(fun, 0);
        final Today today = of.createToday();
        ZeroOperandExpressionInvocation invocation = new ZeroOperandExpressionInvocation(today);
        builder.resolveInvocation("System", "Today", invocation);
        return invocation;
    }

    private ZeroOperandExpressionInvocation resolveTimeOfDay(FunctionRef fun) {
        checkNumberOfOperands(fun, 0);
        final TimeOfDay timeOfDay = of.createTimeOfDay();
        ZeroOperandExpressionInvocation invocation = new ZeroOperandExpressionInvocation(timeOfDay);
        builder.resolveInvocation("System", "TimeOfDay", invocation);
        return invocation;
    }

    // List Function Support

    private IndexOfInvocation resolveIndexOf(FunctionRef fun) {
        checkNumberOfOperands(fun, 2);
        final IndexOf indexOf = of.createIndexOf();
        indexOf.setSource(fun.getOperand().get(0));
        indexOf.setElement(fun.getOperand().get(1));
        IndexOfInvocation invocation = new IndexOfInvocation(indexOf);
        builder.resolveInvocation("System", "IndexOf", invocation);
        return invocation;
    }

    private FirstInvocation resolveFirst(FunctionRef fun) {
        checkNumberOfOperands(fun, 1);
        final First first = of.createFirst();
        first.setSource(fun.getOperand().get(0));
        FirstInvocation invocation = new FirstInvocation(first);
        builder.resolveInvocation("System", "First", invocation);
        return invocation;
    }

    private LastInvocation resolveLast(FunctionRef fun) {
        checkNumberOfOperands(fun, 1);
        final Last last = of.createLast();
        last.setSource(fun.getOperand().get(0));
        LastInvocation invocation = new LastInvocation(last);
        builder.resolveInvocation("System", "Last", invocation);
        return invocation;
    }

    private SkipInvocation resolveSkip(FunctionRef fun) {
        checkNumberOfOperands(fun, 2);
        Slice slice = of.createSlice();
        slice.setSource(fun.getOperand().get(0));
        slice.setStartIndex(fun.getOperand().get(1));
        slice.setEndIndex(builder.buildNull(fun.getOperand().get(1).getResultType()));
        SkipInvocation invocation = new SkipInvocation(slice);
        builder.resolveInvocation("System", "Skip", invocation);
        return invocation;
    }

    private TakeInvocation resolveTake(FunctionRef fun) {
        checkNumberOfOperands(fun, 2);
        Slice slice = of.createSlice();
        slice.setSource(fun.getOperand().get(0));
        slice.setStartIndex(builder.createLiteral(0));
        Coalesce coalesce = of.createCoalesce().withOperand(fun.getOperand().get(1), builder.createLiteral(0));
        NaryExpressionInvocation naryInvocation = new NaryExpressionInvocation(coalesce);
        builder.resolveInvocation("System", "Coalesce", naryInvocation);
        slice.setEndIndex(coalesce);
        TakeInvocation invocation = new TakeInvocation(slice);
        builder.resolveInvocation("System", "Take", invocation);
        return invocation;
    }

    private TailInvocation resolveTail(FunctionRef fun) {
        checkNumberOfOperands(fun, 1);
        Slice slice = of.createSlice();
        slice.setSource(fun.getOperand().get(0));
        slice.setStartIndex(builder.createLiteral(1));
        slice.setEndIndex(builder.buildNull(builder.resolveTypeName("System", "Integer")));
        TailInvocation invocation = new TailInvocation(slice);
        builder.resolveInvocation("System", "Tail", invocation);
        return invocation;
    }

    // String Function Support

    private CombineInvocation resolveCombine(FunctionRef fun) {
        if (fun.getOperand().isEmpty() || fun.getOperand().size() > 2) {
            throw new IllegalArgumentException(
                    "Could not resolve call to system operator Combine.  Expected 1 or 2 arguments.");
        }
        final Combine combine = of.createCombine().withSource(fun.getOperand().get(0));
        if (fun.getOperand().size() == 2) {
            combine.setSeparator(fun.getOperand().get(1));
        }
        CombineInvocation invocation = new CombineInvocation(combine);
        builder.resolveInvocation("System", "Combine", invocation);
        return invocation;
    }

    private SplitInvocation resolveSplit(FunctionRef fun) {
        checkNumberOfOperands(fun, 2);
        final Split split = of.createSplit()
                .withStringToSplit(fun.getOperand().get(0))
                .withSeparator(fun.getOperand().get(1));
        SplitInvocation invocation = new SplitInvocation(split);
        builder.resolveInvocation("System", "Split", invocation);
        return invocation;
    }

    private SplitOnMatchesInvocation resolveSplitOnMatches(FunctionRef fun) {
        checkNumberOfOperands(fun, 2);
        final SplitOnMatches splitOnMatches = of.createSplitOnMatches()
                .withStringToSplit(fun.getOperand().get(0))
                .withSeparatorPattern(fun.getOperand().get(1));
        SplitOnMatchesInvocation invocation = new SplitOnMatchesInvocation(splitOnMatches);
        builder.resolveInvocation("System", "SplitOnMatches", invocation);
        return invocation;
    }

    private PositionOfInvocation resolvePositionOf(FunctionRef fun) {
        checkNumberOfOperands(fun, 2);
        final PositionOf pos = of.createPositionOf()
                .withPattern(fun.getOperand().get(0))
                .withString(fun.getOperand().get(1));
        PositionOfInvocation invocation = new PositionOfInvocation(pos);
        builder.resolveInvocation("System", "PositionOf", invocation);
        return invocation;
    }

    private LastPositionOfInvocation resolveLastPositionOf(FunctionRef fun) {
        checkNumberOfOperands(fun, 2);
        final LastPositionOf pos = of.createLastPositionOf()
                .withPattern(fun.getOperand().get(0))
                .withString(fun.getOperand().get(1));
        LastPositionOfInvocation invocation = new LastPositionOfInvocation(pos);
        builder.resolveInvocation("System", "LastPositionOf", invocation);
        return invocation;
    }

    private SubstringInvocation resolveSubstring(FunctionRef fun) {
        if (fun.getOperand().size() < 2 || fun.getOperand().size() > 3) {
            throw new IllegalArgumentException(
                    "Could not resolve call to system operator Substring.  Expected 2 or 3 arguments.");
        }
        final Substring substring = of.createSubstring()
                .withStringToSub(fun.getOperand().get(0))
                .withStartIndex(fun.getOperand().get(1));
        if (fun.getOperand().size() == 3) {
            substring.setLength(fun.getOperand().get(2));
        }
        SubstringInvocation invocation = new SubstringInvocation(substring);
        builder.resolveInvocation("System", "Substring", invocation);
        return invocation;
    }

    // Error Functions
    private MessageInvocation resolveMessage(FunctionRef fun) {
        if (fun.getOperand().size() != 5) {
            throw new IllegalArgumentException(
                    "Could not resolve call to system operator Message. Expected 5 arguments.");
        }

        Message message = of.createMessage()
                .withSource(fun.getOperand().get(0))
                .withCondition(fun.getOperand().get(1))
                .withCode(fun.getOperand().get(2))
                .withSeverity(fun.getOperand().get(3))
                .withMessage(fun.getOperand().get(4));

        MessageInvocation invocation = new MessageInvocation(message);
        builder.resolveInvocation("System", "Message", invocation);
        return invocation;
    }

    // Type Functions

    private ConvertInvocation resolveConvert(FunctionRef fun) {
        checkNumberOfOperands(fun, 1);
        final Convert convert = of.createConvert().withOperand(fun.getOperand().get(0));
        final SystemModel sm = builder.getSystemModel();
        switch (fun.getName()) {
            case "ToString":
                convert.setToType(builder.dataTypeToQName(sm.getString()));
                break;
            case "ToBoolean":
                convert.setToType(builder.dataTypeToQName(sm.getBoolean()));
                break;
            case "ToInteger":
                convert.setToType(builder.dataTypeToQName(sm.getInteger()));
                break;
            case "ToLong":
                convert.setToType(builder.dataTypeToQName(sm.getLong()));
                break;
            case "ToDecimal":
                convert.setToType(builder.dataTypeToQName(sm.getDecimal()));
                break;
            case "ToQuantity":
                convert.setToType(builder.dataTypeToQName(sm.getQuantity()));
                break;
            case "ToRatio":
                convert.setToType(builder.dataTypeToQName(sm.getRatio()));
                break;
            case "ToDate":
                convert.setToType(builder.dataTypeToQName(sm.getDate()));
                break;
            case "ToDateTime":
                convert.setToType(builder.dataTypeToQName(sm.getDateTime()));
                break;
            case "ToTime":
                convert.setToType(builder.dataTypeToQName(sm.getTime()));
                break;
            case "ToConcept":
                convert.setToType(builder.dataTypeToQName(sm.getConcept()));
                break;
            default:
                throw new IllegalArgumentException(String.format(
                        "Could not resolve call to system operator %s. Unknown conversion type.", fun.getName()));
        }
        ConvertInvocation invocation = new ConvertInvocation(convert);
        builder.resolveInvocation("System", fun.getName(), invocation);
        return invocation;
    }

    // General Function Support

    @SuppressWarnings("unchecked")
    private  T createExpression(FunctionRef fun) {
        try {
            return (T) of.getClass().getMethod("create" + fun.getName()).invoke(of);
        } catch (Exception e) {
            throw new CqlInternalException(
                    String.format("Could not create instance of Element \"%s\"", fun.getName()),
                    !fun.getTrackbacks().isEmpty() ? fun.getTrackbacks().get(0) : null,
                    e);
        }
    }

    private UnaryExpressionInvocation resolveUnary(FunctionRef fun) {
        UnaryExpression operator = createExpression(fun);
        checkNumberOfOperands(fun, 1);
        operator.setOperand(fun.getOperand().get(0));
        UnaryExpressionInvocation invocation = new UnaryExpressionInvocation(operator);
        builder.resolveInvocation("System", fun.getName(), invocation);
        return invocation;
    }

    private BinaryExpressionInvocation resolveBinary(FunctionRef fun) {
        BinaryExpression operator = createExpression(fun);
        checkNumberOfOperands(fun, 2);
        operator.getOperand().addAll(fun.getOperand());
        BinaryExpressionInvocation invocation = new BinaryExpressionInvocation(operator);
        builder.resolveInvocation("System", fun.getName(), invocation);
        return invocation;
    }

    private TernaryExpressionInvocation resolveTernary(FunctionRef fun) {
        TernaryExpression operator = createExpression(fun);
        checkNumberOfOperands(fun, 3);
        operator.getOperand().addAll(fun.getOperand());
        TernaryExpressionInvocation invocation = new TernaryExpressionInvocation(operator);
        builder.resolveInvocation("System", fun.getName(), invocation);
        return invocation;
    }

    private NaryExpressionInvocation resolveNary(FunctionRef fun) {
        NaryExpression operator = createExpression(fun);
        operator.getOperand().addAll(fun.getOperand());
        NaryExpressionInvocation invocation = new NaryExpressionInvocation(operator);
        builder.resolveInvocation("System", fun.getName(), invocation);
        return invocation;
    }

    private AggregateExpressionInvocation resolveAggregate(FunctionRef fun) {
        AggregateExpression operator = createExpression(fun);
        checkNumberOfOperands(fun, 1);
        operator.setSource(fun.getOperand().get(0));
        AggregateExpressionInvocation invocation = new AggregateExpressionInvocation(operator);
        builder.resolveInvocation("System", fun.getName(), invocation);
        return invocation;
    }

    private void checkNumberOfOperands(FunctionRef fun, int expectedOperands) {
        if (fun.getOperand().size() != expectedOperands) {
            throw new IllegalArgumentException(String.format(
                    "Could not resolve call to system operator %s.  Expected %d arguments.",
                    fun.getName(), expectedOperands));
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy