public ExpressionNode toExpressionNode(GroupingExpression exp) {
        if (exp instanceof AddFunction addFunction) {
            return addArguments(new AddFunctionNode(), addFunction);
        }
        if (exp instanceof AggregatorNode) {
            return new AggregationRefNode(toAggregationResult(exp));
        }
        if (exp instanceof AndFunction andFunction) {
            return addArguments(new AndFunctionNode(), andFunction);
        }
        if (exp instanceof AttributeMapLookupValue mapLookup) {
            if (mapLookup.hasKeySourceAttribute()) {
                return AttributeMapLookupNode.fromKeySourceAttribute(mapLookup.getAttributeName(),
                        mapLookup.getKeyAttribute(), mapLookup.getValueAttribute(), mapLookup.getKeySourceAttribute());
            } else {
                return AttributeMapLookupNode.fromKey(mapLookup.getAttributeName(),
                        mapLookup.getKeyAttribute(), mapLookup.getValueAttribute(), mapLookup.getKey());
            }
        }
        if (exp instanceof AttributeValue value) {
            return new AttributeNode(value.getAttributeName());
        }
        if (exp instanceof AttributeFunction function) {
            return new AttributeNode(function.getAttributeName());
        }
        if (exp instanceof CatFunction function) {
            return addArguments(new CatFunctionNode(), function);
        }
        if (exp instanceof DebugWaitFunction waitFunction) {
            return new DebugWaitFunctionNode(toExpressionNode(waitFunction.getArg(0)),
                                             waitFunction.getWaitTime(),
                                             waitFunction.getBusyWait());
        }
        if (exp instanceof DocIdNsSpecificValue) {
            return new GetDocIdNamespaceSpecificFunctionNode();
        }
        if (exp instanceof DoubleValue value) {
            return new ConstantNode(new FloatResultNode(value.getValue()));
        }
        if (exp instanceof DivFunction divFunction) {
            return addArguments(new DivideFunctionNode(), divFunction);
        }
        if (exp instanceof FixedWidthFunction fixedWidthFunction) {
            Number w = fixedWidthFunction.getWidth();
            return new FixedWidthBucketFunctionNode(
                    w instanceof Double ? new FloatResultNode(w.doubleValue()) : new IntegerResultNode(w.longValue()),
                    toExpressionNode(fixedWidthFunction.getArg(0)));
        }
        if (exp instanceof LongValue value) {
            return new ConstantNode(new IntegerResultNode(value.getValue()));
        }
        if (exp instanceof MaxFunction maxFunction) {
            return addArguments(new MaxFunctionNode(), maxFunction);
        }
        if (exp instanceof Md5Function md5Function) {
            return new MD5BitFunctionNode().setNumBits(md5Function.getNumBits())
                                           .addArg(toExpressionNode(md5Function.getArg(0)));
        }
        if (exp instanceof UcaFunction uca) {
            return new UcaFunctionNode(toExpressionNode(uca.getArg(0)), uca.getLocale(), uca.getStrength());
        }
        if (exp instanceof MinFunction minFunction) {
            return addArguments(new MinFunctionNode(), minFunction);
        }
        if (exp instanceof ModFunction modFunction) {
            return addArguments(new ModuloFunctionNode(), modFunction);
        }
        if (exp instanceof MulFunction mulFunction) {
            return addArguments(new MultiplyFunctionNode(), mulFunction);
        }
        if (exp instanceof NegFunction negFunction) {
            return new NegateFunctionNode(toExpressionNode(negFunction.getArg(0)));
        }
        if (exp instanceof NormalizeSubjectFunction normalizeSubjectFunction) {
            return new NormalizeSubjectFunctionNode(toExpressionNode(normalizeSubjectFunction.getArg(0)));
        }
        if (exp instanceof NowFunction) {
            return new ConstantNode(new IntegerResultNode(System.currentTimeMillis() / 1000));
        }
        if (exp instanceof OrFunction orFunction) {
            return addArguments(new OrFunctionNode(), orFunction);
        }
        if (exp instanceof PredefinedFunction predefinedFunction) {
            return new RangeBucketPreDefFunctionNode(toBucketList(predefinedFunction),
                                                     toExpressionNode(predefinedFunction.getArg(0)));
        }
        if (exp instanceof RelevanceValue) {
            return new RelevanceNode();
        }
        if (exp instanceof ReverseFunction reverseFunction) {
            return new ReverseFunctionNode(toExpressionNode(reverseFunction.getArg(0)));
        }
        if (exp instanceof SizeFunction sizeFunction) {
            return new NumElemFunctionNode(toExpressionNode(sizeFunction.getArg(0)));
        }
        if (exp instanceof SortFunction sortFunction) {
            return new SortFunctionNode(toExpressionNode(sortFunction.getArg(0)));
        }
        if (exp instanceof ArrayAtLookup lookup) {
            return new ArrayAtLookupNode(lookup.getAttributeName(), toExpressionNode(lookup.getIndexArgument()));
        }
        if (exp instanceof InterpolatedLookup lookup) {
            return new InterpolatedLookupNode(lookup.getAttributeName(), toExpressionNode(lookup.getLookupArgument()));
        }
        if (exp instanceof StrCatFunction strCatFunction) {
            return addArguments(new StrCatFunctionNode(), strCatFunction);
        }
        if (exp instanceof StringValue value) {
            return new ConstantNode(new StringResultNode(value.getValue()));
        }
        if (exp instanceof StrLenFunction strLenFunction) {
            return new StrLenFunctionNode(toExpressionNode(strLenFunction.getArg(0)));
        }
        if (exp instanceof SubFunction subFunction) {
            return toSubNode(subFunction);
        }
        if (exp instanceof ToDoubleFunction toDoubleFunction) {
            return new ToFloatFunctionNode(toExpressionNode(toDoubleFunction.getArg(0)));
        }
        if (exp instanceof ToLongFunction toLongFunction) {
            return new ToIntFunctionNode(toExpressionNode(toLongFunction.getArg(0)));
        }
        if (exp instanceof ToRawFunction toRawFunction) {
            return new ToRawFunctionNode(toExpressionNode(toRawFunction.getArg(0)));
        }
        if (exp instanceof ToStringFunction toStringFunction) {
            return new ToStringFunctionNode(toExpressionNode(toStringFunction.getArg(0)));
        }
        if (exp instanceof DateFunction dateFunction) {
            StrCatFunctionNode ret = new StrCatFunctionNode();
            GroupingExpression arg = dateFunction.getArg(0);
            ret.addArg(new ToStringFunctionNode(toTime(arg, TimeStampFunctionNode.TimePart.Year)));
            ret.addArg(new ConstantNode(new StringResultNode("-")));
            ret.addArg(new ToStringFunctionNode(toTime(arg, TimeStampFunctionNode.TimePart.Month)));
            ret.addArg(new ConstantNode(new StringResultNode("-")));
            ret.addArg(new ToStringFunctionNode(toTime(arg, TimeStampFunctionNode.TimePart.MonthDay)));
            return ret;
        }
        if (exp instanceof MathSqrtFunction mathSqrtFunction) {
            return new MathFunctionNode(toExpressionNode(mathSqrtFunction.getArg(0)),
                                        MathFunctionNode.Function.SQRT);
        }
        if (exp instanceof MathCbrtFunction mathCbrtFunction) {
            return new MathFunctionNode(toExpressionNode(mathCbrtFunction.getArg(0)),
                                        MathFunctionNode.Function.CBRT);
        }
        if (exp instanceof MathLogFunction mathLogFunction) {
            return new MathFunctionNode(toExpressionNode(mathLogFunction.getArg(0)),
                                        MathFunctionNode.Function.LOG);
        }
        if (exp instanceof MathLog1pFunction mathLog1pFunction) {
            return new MathFunctionNode(toExpressionNode(mathLog1pFunction.getArg(0)),
                                        MathFunctionNode.Function.LOG1P);
        }
        if (exp instanceof MathLog10Function mathLog10Function) {
            return new MathFunctionNode(toExpressionNode(mathLog10Function.getArg(0)),
                                        MathFunctionNode.Function.LOG10);
        }
        if (exp instanceof MathExpFunction mathExpFunction) {
            return new MathFunctionNode(toExpressionNode(mathExpFunction.getArg(0)),
                                        MathFunctionNode.Function.EXP);
        }
        if (exp instanceof MathPowFunction mathPowFunction) {
            return new MathFunctionNode(toExpressionNode(mathPowFunction.getArg(0)),
                                        MathFunctionNode.Function.POW)
                    .addArg(toExpressionNode(mathPowFunction.getArg(1)));
        }
        if (exp instanceof MathHypotFunction mathHypotFunction) {
            return new MathFunctionNode(toExpressionNode(mathHypotFunction.getArg(0)),
                                        MathFunctionNode.Function.HYPOT)
                    .addArg(toExpressionNode(mathHypotFunction.getArg(1)));
        }
        if (exp instanceof MathSinFunction mathSinFunction) {
            return new MathFunctionNode(toExpressionNode(mathSinFunction.getArg(0)),
                                        MathFunctionNode.Function.SIN);
        }
        if (exp instanceof MathASinFunction mathASinFunction) {
            return new MathFunctionNode(toExpressionNode(mathASinFunction.getArg(0)),
                                        MathFunctionNode.Function.ASIN);
        }
        if (exp instanceof MathCosFunction mathCosFunction) {
            return new MathFunctionNode(toExpressionNode(mathCosFunction.getArg(0)),
                                        MathFunctionNode.Function.COS);
        }
        if (exp instanceof MathACosFunction mathACosFunction) {
            return new MathFunctionNode(toExpressionNode(mathACosFunction.getArg(0)),
                                        MathFunctionNode.Function.ACOS);
        }
        if (exp instanceof MathTanFunction mathTanFunction) {
            return new MathFunctionNode(toExpressionNode(mathTanFunction.getArg(0)),
                                        MathFunctionNode.Function.TAN);
        }
        if (exp instanceof MathATanFunction mathATanFunction) {
            return new MathFunctionNode(toExpressionNode(mathATanFunction.getArg(0)),
                                        MathFunctionNode.Function.ATAN);
        }
        if (exp instanceof MathSinHFunction mathSinHFunction) {
            return new MathFunctionNode(toExpressionNode(mathSinHFunction.getArg(0)),
                                        MathFunctionNode.Function.SINH);
        }
        if (exp instanceof MathASinHFunction mathASinHFunction) {
            return new MathFunctionNode(toExpressionNode(mathASinHFunction.getArg(0)),
                                        MathFunctionNode.Function.ASINH);
        }
        if (exp instanceof MathCosHFunction mathCosHFunction) {
            return new MathFunctionNode(toExpressionNode(mathCosHFunction.getArg(0)),
                                        MathFunctionNode.Function.COSH);
        }
        if (exp instanceof MathACosHFunction mathACosHFunction) {
            return new MathFunctionNode(toExpressionNode(mathACosHFunction.getArg(0)),
                                        MathFunctionNode.Function.ACOSH);
        }
        if (exp instanceof MathTanHFunction mathTanHFunction) {
            return new MathFunctionNode(toExpressionNode(mathTanHFunction.getArg(0)),
                                        MathFunctionNode.Function.TANH);
        }
        if (exp instanceof MathATanHFunction mathATanHFunction) {
            return new MathFunctionNode(toExpressionNode(mathATanHFunction.getArg(0)),
                                        MathFunctionNode.Function.ATANH);
        }
        if (exp instanceof MathFloorFunction mathFloorFunction) {
            return new MathFunctionNode(toExpressionNode(mathFloorFunction.getArg(0)),
                                        MathFunctionNode.Function.FLOOR);
        }
        if (exp instanceof ZCurveXFunction zCurveXFunction) {
            return new ZCurveFunctionNode(toExpressionNode(zCurveXFunction.getArg(0)),
                                          ZCurveFunctionNode.Dimension.X);
        }
        if (exp instanceof ZCurveYFunction zCurveYFunction) {
            return new ZCurveFunctionNode(toExpressionNode(zCurveYFunction.getArg(0)),
                                          ZCurveFunctionNode.Dimension.Y);
        }
        if (exp instanceof DayOfMonthFunction dayOfMonthFunction) {
            return toTime(dayOfMonthFunction.getArg(0), TimeStampFunctionNode.TimePart.MonthDay);
        }
        if (exp instanceof DayOfWeekFunction dayOfWeekFunction) {
            return toTime(dayOfWeekFunction.getArg(0), TimeStampFunctionNode.TimePart.WeekDay);
        }
        if (exp instanceof DayOfYearFunction dayOfYearFunction) {
            return toTime(dayOfYearFunction.getArg(0), TimeStampFunctionNode.TimePart.YearDay);
        }
        if (exp instanceof HourOfDayFunction hourOfDayFunction) {
            return toTime(hourOfDayFunction.getArg(0), TimeStampFunctionNode.TimePart.Hour);
        }
        if (exp instanceof MinuteOfHourFunction minuteOfHourFunction) {
            return toTime(minuteOfHourFunction.getArg(0), TimeStampFunctionNode.TimePart.Minute);
        }
        if (exp instanceof MonthOfYearFunction monthOfYearFunction) {
            return toTime(monthOfYearFunction.getArg(0), TimeStampFunctionNode.TimePart.Month);
        }
        if (exp instanceof SecondOfMinuteFunction secondOfMinuteFunction) {
            return toTime(secondOfMinuteFunction.getArg(0), TimeStampFunctionNode.TimePart.Second);
        }
        if (exp instanceof YearFunction yearFunction) {
            return toTime(yearFunction.getArg(0), TimeStampFunctionNode.TimePart.Year);
        }
        if (exp instanceof XorFunction xorFunction) {
            return addArguments(new XorFunctionNode(), xorFunction);
        }
        if (exp instanceof XorBitFunction xorBitFunction) {
            return new XorBitFunctionNode().setNumBits(xorBitFunction.getNumBits())
                                           .addArg(toExpressionNode(xorBitFunction.getArg(0)));
        }
        throw new IllegalInputException("Can not convert '" + exp + "' of class " + exp.getClass().getName() +
                                        " to an expression.");
    }
Converts the given ast type grouping expression to a corresponding back-end type expression.

@param exp The expression to convert.
@return The corresponding back-end expression.
@throws IllegalInputException Thrown if the given expression could not be converted.
container-search/src/main/java/com/yahoo/search/grouping/vespa/ExpressionConverter.java