Search in sources :

Example 1 with ExpCompiler

use of mondrian.calc.ExpCompiler in project mondrian by pentaho.

the class BuiltinFunTable method defineFunctions.

public void defineFunctions(Builder builder) {
    builder.defineReserved("NULL");
    // Empty expression
    builder.define(new FunDefBase("", "", "Dummy function representing the empty expression", Syntax.Empty, Category.Empty, new int[0]) {
    });
    // "SetToArray(<Set>[, <Set>]...[, <Numeric Expression>])"
    if (false)
        builder.define(new FunDefBase("SetToArray", "SetToArray(<Set>[, <Set>]...[, <Numeric Expression>])", "Converts one or more sets to an array for use in a user-defined function.", "fa*") {

            public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
                throw new UnsupportedOperationException();
            }
        });
    // 
    // DIMENSION FUNCTIONS
    builder.define(HierarchyDimensionFunDef.instance);
    // "<Dimension>.Dimension"
    builder.define(DimensionDimensionFunDef.INSTANCE);
    // "<Level>.Dimension"
    builder.define(LevelDimensionFunDef.INSTANCE);
    // "<Member>.Dimension"
    builder.define(MemberDimensionFunDef.INSTANCE);
    // "Dimensions(<Numeric Expression>)"
    builder.define(DimensionsNumericFunDef.INSTANCE);
    // "Dimensions(<String Expression>)"
    builder.define(DimensionsStringFunDef.INSTANCE);
    // 
    // HIERARCHY FUNCTIONS
    builder.define(LevelHierarchyFunDef.instance);
    builder.define(MemberHierarchyFunDef.instance);
    // 
    // LEVEL FUNCTIONS
    builder.define(MemberLevelFunDef.instance);
    // "<Hierarchy>.Levels(<Numeric Expression>)"
    builder.define(new FunDefBase("Levels", "Returns the level whose position in a hierarchy is specified by a numeric expression.", "mlhn") {

        public Type getResultType(Validator validator, Exp[] args) {
            final Type argType = args[0].getType();
            return LevelType.forType(argType);
        }

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final HierarchyCalc hierarchyCalc = compiler.compileHierarchy(call.getArg(0));
            final IntegerCalc ordinalCalc = compiler.compileInteger(call.getArg(1));
            return new AbstractLevelCalc(call, new Calc[] { hierarchyCalc, ordinalCalc }) {

                public Level evaluateLevel(Evaluator evaluator) {
                    Hierarchy hierarchy = hierarchyCalc.evaluateHierarchy(evaluator);
                    int ordinal = ordinalCalc.evaluateInteger(evaluator);
                    return nthLevel(hierarchy, ordinal);
                }
            };
        }

        Level nthLevel(Hierarchy hierarchy, int n) {
            Level[] levels = hierarchy.getLevels();
            if (n >= levels.length || n < 0) {
                throw newEvalException(this, "Index '" + n + "' out of bounds");
            }
            return levels[n];
        }
    });
    // "<Hierarchy>.Levels(<String Expression>)"
    builder.define(new FunDefBase("Levels", "Returns the level whose name is specified by a string expression.", "mlhS") {

        public Type getResultType(Validator validator, Exp[] args) {
            final Type argType = args[0].getType();
            return LevelType.forType(argType);
        }

        public Calc compileCall(final ResolvedFunCall call, ExpCompiler compiler) {
            final HierarchyCalc hierarchyCalc = compiler.compileHierarchy(call.getArg(0));
            final StringCalc nameCalc = compiler.compileString(call.getArg(1));
            return new AbstractLevelCalc(call, new Calc[] { hierarchyCalc, nameCalc }) {

                public Level evaluateLevel(Evaluator evaluator) {
                    Hierarchy hierarchy = hierarchyCalc.evaluateHierarchy(evaluator);
                    String name = nameCalc.evaluateString(evaluator);
                    for (Level level : hierarchy.getLevels()) {
                        if (level.getName().equals(name)) {
                            return level;
                        }
                    }
                    throw newEvalException(call.getFunDef(), "Level '" + name + "' not found in hierarchy '" + hierarchy + "'");
                }
            };
        }
    });
    // "Levels(<String Expression>)"
    builder.define(new FunDefBase("Levels", "Returns the level whose name is specified by a string expression.", "flS") {

        public Type getResultType(Validator validator, Exp[] args) {
            final Type argType = args[0].getType();
            return LevelType.forType(argType);
        }

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final StringCalc stringCalc = compiler.compileString(call.getArg(0));
            return new AbstractLevelCalc(call, new Calc[] { stringCalc }) {

                public Level evaluateLevel(Evaluator evaluator) {
                    String levelName = stringCalc.evaluateString(evaluator);
                    return findLevel(evaluator, levelName);
                }
            };
        }

        Level findLevel(Evaluator evaluator, String s) {
            Cube cube = evaluator.getCube();
            OlapElement o = (s.startsWith("[")) ? evaluator.getSchemaReader().lookupCompound(cube, parseIdentifier(s), false, Category.Level) : // brackets, so don't even try
            null;
            if (o instanceof Level) {
                return (Level) o;
            } else if (o == null) {
                throw newEvalException(this, "Level '" + s + "' not found");
            } else {
                throw newEvalException(this, "Levels('" + s + "') found " + o);
            }
        }
    });
    // 
    // LOGICAL FUNCTIONS
    builder.define(IsEmptyFunDef.FunctionResolver);
    builder.define(IsEmptyFunDef.PostfixResolver);
    builder.define(IsNullFunDef.Resolver);
    builder.define(IsFunDef.Resolver);
    builder.define(AsFunDef.RESOLVER);
    // 
    // MEMBER FUNCTIONS
    builder.define(AncestorFunDef.Resolver);
    builder.define(AncestorsFunDef.Resolver);
    builder.define(new FunDefBase("Cousin", "<Member> Cousin(<Member>, <Ancestor Member>)", "Returns the member with the same relative position under <ancestor member> as the member specified.", "fmmm") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final MemberCalc memberCalc = compiler.compileMember(call.getArg(0));
            final MemberCalc ancestorMemberCalc = compiler.compileMember(call.getArg(1));
            return new AbstractMemberCalc(call, new Calc[] { memberCalc, ancestorMemberCalc }) {

                public Member evaluateMember(Evaluator evaluator) {
                    Member member = memberCalc.evaluateMember(evaluator);
                    Member ancestorMember = ancestorMemberCalc.evaluateMember(evaluator);
                    return cousin(evaluator.getSchemaReader(), member, ancestorMember);
                }
            };
        }
    });
    builder.define(HierarchyCurrentMemberFunDef.instance);
    builder.define(NamedSetCurrentFunDef.instance);
    builder.define(NamedSetCurrentOrdinalFunDef.instance);
    // "<Member>.DataMember"
    builder.define(new FunDefBase("DataMember", "Returns the system-generated data member that is associated with a nonleaf member of a dimension.", "pmm") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final MemberCalc memberCalc = compiler.compileMember(call.getArg(0));
            return new AbstractMemberCalc(call, new Calc[] { memberCalc }) {

                public Member evaluateMember(Evaluator evaluator) {
                    Member member = memberCalc.evaluateMember(evaluator);
                    return member.getDataMember();
                }
            };
        }
    });
    // "<Dimension>.DefaultMember". The function is implemented using an
    // implicit cast to hierarchy, and we create a FunInfo for
    // documentation & backwards compatibility.
    builder.define(new FunInfo("DefaultMember", "Returns the default member of a dimension.", "pmd"));
    // "<Hierarchy>.DefaultMember"
    builder.define(new FunDefBase("DefaultMember", "Returns the default member of a hierarchy.", "pmh") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final HierarchyCalc hierarchyCalc = compiler.compileHierarchy(call.getArg(0));
            return new AbstractMemberCalc(call, new Calc[] { hierarchyCalc }) {

                public Member evaluateMember(Evaluator evaluator) {
                    Hierarchy hierarchy = hierarchyCalc.evaluateHierarchy(evaluator);
                    return evaluator.getSchemaReader().getHierarchyDefaultMember(hierarchy);
                }
            };
        }
    });
    // "<Member>.FirstChild"
    builder.define(new FunDefBase("FirstChild", "Returns the first child of a member.", "pmm") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final MemberCalc memberCalc = compiler.compileMember(call.getArg(0));
            return new AbstractMemberCalc(call, new Calc[] { memberCalc }) {

                public Member evaluateMember(Evaluator evaluator) {
                    Member member = memberCalc.evaluateMember(evaluator);
                    return firstChild(evaluator, member);
                }
            };
        }

        Member firstChild(Evaluator evaluator, Member member) {
            List<Member> children = evaluator.getSchemaReader().getMemberChildren(member);
            return (children.size() == 0) ? member.getHierarchy().getNullMember() : children.get(0);
        }
    });
    // <Member>.FirstSibling
    builder.define(new FunDefBase("FirstSibling", "Returns the first child of the parent of a member.", "pmm") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final MemberCalc memberCalc = compiler.compileMember(call.getArg(0));
            return new AbstractMemberCalc(call, new Calc[] { memberCalc }) {

                public Member evaluateMember(Evaluator evaluator) {
                    Member member = memberCalc.evaluateMember(evaluator);
                    return firstSibling(member, evaluator);
                }
            };
        }

        Member firstSibling(Member member, Evaluator evaluator) {
            Member parent = member.getParentMember();
            List<Member> children;
            final SchemaReader schemaReader = evaluator.getSchemaReader();
            if (parent == null) {
                if (member.isNull()) {
                    return member;
                }
                children = schemaReader.getHierarchyRootMembers(member.getHierarchy());
            } else {
                children = schemaReader.getMemberChildren(parent);
            }
            return children.get(0);
        }
    });
    builder.define(LeadLagFunDef.LagResolver);
    // <Member>.LastChild
    builder.define(new FunDefBase("LastChild", "Returns the last child of a member.", "pmm") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final MemberCalc memberCalc = compiler.compileMember(call.getArg(0));
            return new AbstractMemberCalc(call, new Calc[] { memberCalc }) {

                public Member evaluateMember(Evaluator evaluator) {
                    Member member = memberCalc.evaluateMember(evaluator);
                    return lastChild(evaluator, member);
                }
            };
        }

        Member lastChild(Evaluator evaluator, Member member) {
            List<Member> children = evaluator.getSchemaReader().getMemberChildren(member);
            return (children.size() == 0) ? member.getHierarchy().getNullMember() : children.get(children.size() - 1);
        }
    });
    // <Member>.LastSibling
    builder.define(new FunDefBase("LastSibling", "Returns the last child of the parent of a member.", "pmm") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final MemberCalc memberCalc = compiler.compileMember(call.getArg(0));
            return new AbstractMemberCalc(call, new Calc[] { memberCalc }) {

                public Member evaluateMember(Evaluator evaluator) {
                    Member member = memberCalc.evaluateMember(evaluator);
                    return firstSibling(member, evaluator);
                }
            };
        }

        Member firstSibling(Member member, Evaluator evaluator) {
            Member parent = member.getParentMember();
            List<Member> children;
            final SchemaReader schemaReader = evaluator.getSchemaReader();
            if (parent == null) {
                if (member.isNull()) {
                    return member;
                }
                children = schemaReader.getHierarchyRootMembers(member.getHierarchy());
            } else {
                children = schemaReader.getMemberChildren(parent);
            }
            return children.get(children.size() - 1);
        }
    });
    builder.define(LeadLagFunDef.LeadResolver);
    // Members(<String Expression>)
    builder.define(new FunDefBase("Members", "Returns the member whose name is specified by a string expression.", "fmS") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            throw new UnsupportedOperationException();
        }
    });
    // <Member>.NextMember
    builder.define(new FunDefBase("NextMember", "Returns the next member in the level that contains a specified member.", "pmm") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final MemberCalc memberCalc = compiler.compileMember(call.getArg(0));
            return new AbstractMemberCalc(call, new Calc[] { memberCalc }) {

                public Member evaluateMember(Evaluator evaluator) {
                    Member member = memberCalc.evaluateMember(evaluator);
                    return evaluator.getSchemaReader().getLeadMember(member, 1);
                }
            };
        }
    });
    builder.define(OpeningClosingPeriodFunDef.OpeningPeriodResolver);
    builder.define(OpeningClosingPeriodFunDef.ClosingPeriodResolver);
    builder.define(MemberOrderKeyFunDef.instance);
    builder.define(ParallelPeriodFunDef.Resolver);
    // <Member>.Parent
    builder.define(new FunDefBase("Parent", "Returns the parent of a member.", "pmm") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final MemberCalc memberCalc = compiler.compileMember(call.getArg(0));
            return new AbstractMemberCalc(call, new Calc[] { memberCalc }) {

                public Member evaluateMember(Evaluator evaluator) {
                    Member member = memberCalc.evaluateMember(evaluator);
                    return memberParent(evaluator, member);
                }
            };
        }

        Member memberParent(Evaluator evaluator, Member member) {
            Member parent = evaluator.getSchemaReader().getMemberParent(member);
            if (parent == null) {
                parent = member.getHierarchy().getNullMember();
            }
            return parent;
        }
    });
    // <Member>.PrevMember
    builder.define(new FunDefBase("PrevMember", "Returns the previous member in the level that contains a specified member.", "pmm") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final MemberCalc memberCalc = compiler.compileMember(call.getArg(0));
            return new AbstractMemberCalc(call, new Calc[] { memberCalc }) {

                public Member evaluateMember(Evaluator evaluator) {
                    Member member = memberCalc.evaluateMember(evaluator);
                    return evaluator.getSchemaReader().getLeadMember(member, -1);
                }
            };
        }
    });
    builder.define(StrToMemberFunDef.INSTANCE);
    builder.define(ValidMeasureFunDef.instance);
    // 
    // NUMERIC FUNCTIONS
    builder.define(AggregateFunDef.resolver);
    // Obsolete??
    builder.define(new MultiResolver("$AggregateChildren", "$AggregateChildren(<Hierarchy>)", "Equivalent to 'Aggregate(<Hierarchy>.CurrentMember.Children); for internal use.", new String[] { "Inh" }) {

        protected FunDef createFunDef(Exp[] args, FunDef dummyFunDef) {
            return new FunDefBase(dummyFunDef) {

                public void unparse(Exp[] args, PrintWriter pw) {
                    pw.print(getName());
                    pw.print("(");
                    args[0].unparse(pw);
                    pw.print(")");
                }

                public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
                    final HierarchyCalc hierarchyCalc = compiler.compileHierarchy(call.getArg(0));
                    final Calc valueCalc = new ValueCalc(call);
                    return new GenericCalc(call) {

                        public Object evaluate(Evaluator evaluator) {
                            Hierarchy hierarchy = hierarchyCalc.evaluateHierarchy(evaluator);
                            return aggregateChildren(evaluator, hierarchy, valueCalc);
                        }

                        public Calc[] getCalcs() {
                            return new Calc[] { hierarchyCalc, valueCalc };
                        }
                    };
                }

                Object aggregateChildren(Evaluator evaluator, Hierarchy hierarchy, final Calc valueFunCall) {
                    Member member = evaluator.getPreviousContext(hierarchy);
                    List<Member> members = new ArrayList<Member>();
                    evaluator.getSchemaReader().getParentChildContributingChildren(member.getDataMember(), hierarchy, members);
                    Aggregator aggregator = (Aggregator) evaluator.getProperty(Property.AGGREGATION_TYPE.name, null);
                    if (aggregator == null) {
                        throw FunUtil.newEvalException(null, "Could not find an aggregator in the current " + "evaluation context");
                    }
                    Aggregator rollup = aggregator.getRollup();
                    if (rollup == null) {
                        throw FunUtil.newEvalException(null, "Don't know how to rollup aggregator '" + aggregator + "'");
                    }
                    final int savepoint = evaluator.savepoint();
                    try {
                        final Object o = rollup.aggregate(evaluator, new UnaryTupleList(members), valueFunCall);
                        return o;
                    } finally {
                        evaluator.restore(savepoint);
                    }
                }
            };
        }
    });
    builder.define(AvgFunDef.Resolver);
    builder.define(CorrelationFunDef.Resolver);
    builder.define(CountFunDef.Resolver);
    // <Set>.Count
    builder.define(new FunDefBase("Count", "Returns the number of tuples in a set including empty cells.", "pnx") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final ListCalc listCalc = compiler.compileList(call.getArg(0));
            return new AbstractIntegerCalc(call, new Calc[] { listCalc }) {

                public int evaluateInteger(Evaluator evaluator) {
                    TupleList list = listCalc.evaluateList(evaluator);
                    return count(evaluator, list, true);
                }
            };
        }
    });
    builder.define(CovarianceFunDef.CovarianceResolver);
    builder.define(CovarianceFunDef.CovarianceNResolver);
    builder.define(IifFunDef.STRING_INSTANCE);
    builder.define(IifFunDef.NUMERIC_INSTANCE);
    builder.define(IifFunDef.TUPLE_INSTANCE);
    builder.define(IifFunDef.BOOLEAN_INSTANCE);
    builder.define(IifFunDef.MEMBER_INSTANCE);
    builder.define(IifFunDef.LEVEL_INSTANCE);
    builder.define(IifFunDef.HIERARCHY_INSTANCE);
    builder.define(IifFunDef.DIMENSION_INSTANCE);
    builder.define(IifFunDef.SET_INSTANCE);
    builder.define(LinReg.InterceptResolver);
    builder.define(LinReg.PointResolver);
    builder.define(LinReg.R2Resolver);
    builder.define(LinReg.SlopeResolver);
    builder.define(LinReg.VarianceResolver);
    builder.define(MinMaxFunDef.MaxResolver);
    builder.define(MinMaxFunDef.MinResolver);
    builder.define(MedianFunDef.Resolver);
    builder.define(PercentileFunDef.Resolver);
    // <Level>.Ordinal
    builder.define(new FunDefBase("Ordinal", "Returns the zero-based ordinal value associated with a level.", "pnl") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final LevelCalc levelCalc = compiler.compileLevel(call.getArg(0));
            return new AbstractIntegerCalc(call, new Calc[] { levelCalc }) {

                public int evaluateInteger(Evaluator evaluator) {
                    final Level level = levelCalc.evaluateLevel(evaluator);
                    return level.getDepth();
                }
            };
        }
    });
    builder.define(RankFunDef.Resolver);
    builder.define(CacheFunDef.Resolver);
    builder.define(StdevFunDef.StdevResolver);
    builder.define(StdevFunDef.StddevResolver);
    builder.define(StdevPFunDef.StdevpResolver);
    builder.define(StdevPFunDef.StddevpResolver);
    builder.define(SumFunDef.Resolver);
    // <Measure>.Value
    builder.define(new FunDefBase("Value", "Returns the value of a measure.", "pnm") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final MemberCalc memberCalc = compiler.compileMember(call.getArg(0));
            return new GenericCalc(call) {

                public Object evaluate(Evaluator evaluator) {
                    Member member = memberCalc.evaluateMember(evaluator);
                    final int savepoint = evaluator.savepoint();
                    evaluator.setContext(member);
                    try {
                        Object value = evaluator.evaluateCurrent();
                        return value;
                    } finally {
                        evaluator.restore(savepoint);
                    }
                }

                public boolean dependsOn(Hierarchy hierarchy) {
                    if (super.dependsOn(hierarchy)) {
                        return true;
                    }
                    if (memberCalc.getType().usesHierarchy(hierarchy, true)) {
                        return false;
                    }
                    return true;
                }

                public Calc[] getCalcs() {
                    return new Calc[] { memberCalc };
                }
            };
        }
    });
    builder.define(VarFunDef.VarResolver);
    builder.define(VarFunDef.VarianceResolver);
    builder.define(VarPFunDef.VariancePResolver);
    builder.define(VarPFunDef.VarPResolver);
    // 
    // SET FUNCTIONS
    builder.define(AddCalculatedMembersFunDef.resolver);
    // Ascendants(<Member>)
    builder.define(new FunDefBase("Ascendants", "Returns the set of the ascendants of a specified member.", "fxm") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final MemberCalc memberCalc = compiler.compileMember(call.getArg(0));
            return new AbstractListCalc(call, new Calc[] { memberCalc }) {

                public TupleList evaluateList(Evaluator evaluator) {
                    Member member = memberCalc.evaluateMember(evaluator);
                    return new UnaryTupleList(ascendants(evaluator.getSchemaReader(), member));
                }
            };
        }

        List<Member> ascendants(SchemaReader schemaReader, Member member) {
            if (member.isNull()) {
                return Collections.emptyList();
            }
            final List<Member> result = new ArrayList<Member>();
            result.add(member);
            schemaReader.getMemberAncestors(member, result);
            return result;
        }
    });
    builder.define(TopBottomCountFunDef.BottomCountResolver);
    builder.define(TopBottomPercentSumFunDef.BottomPercentResolver);
    builder.define(TopBottomPercentSumFunDef.BottomSumResolver);
    builder.define(TopBottomCountFunDef.TopCountResolver);
    builder.define(TopBottomPercentSumFunDef.TopPercentResolver);
    builder.define(TopBottomPercentSumFunDef.TopSumResolver);
    // <Member>.Children
    builder.define(new FunDefBase("Children", "Returns the children of a member.", "pxm") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final MemberCalc memberCalc = compiler.compileMember(call.getArg(0));
            return new AbstractListCalc(call, new Calc[] { memberCalc }, false) {

                public TupleList evaluateList(Evaluator evaluator) {
                    // Return the list of children. The list is immutable,
                    // hence 'false' above.
                    Member member = memberCalc.evaluateMember(evaluator);
                    return new UnaryTupleList(getNonEmptyMemberChildren(evaluator, member));
                }
            };
        }
    });
    builder.define(CrossJoinFunDef.Resolver);
    builder.define(NonEmptyCrossJoinFunDef.Resolver);
    builder.define(CrossJoinFunDef.StarResolver);
    builder.define(DescendantsFunDef.Resolver);
    builder.define(DescendantsFunDef.Resolver2);
    builder.define(DistinctFunDef.instance);
    builder.define(DrilldownLevelFunDef.Resolver);
    builder.define(DrilldownLevelTopBottomFunDef.DrilldownLevelTopResolver);
    builder.define(DrilldownLevelTopBottomFunDef.DrilldownLevelBottomResolver);
    builder.define(DrilldownMemberFunDef.Resolver);
    if (false)
        builder.define(new FunDefBase("DrilldownMemberBottom", "DrilldownMemberBottom(<Set1>, <Set2>, <Count>[, [<Numeric Expression>][, RECURSIVE]])", "Like DrilldownMember except that it includes only the bottom N children.", "fx*") {

            public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
                throw new UnsupportedOperationException();
            }
        });
    if (false)
        builder.define(new FunDefBase("DrilldownMemberTop", "DrilldownMemberTop(<Set1>, <Set2>, <Count>[, [<Numeric Expression>][, RECURSIVE]])", "Like DrilldownMember except that it includes only the top N children.", "fx*") {

            public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
                throw new UnsupportedOperationException();
            }
        });
    if (false)
        builder.define(new FunDefBase("DrillupLevel", "DrillupLevel(<Set>[, <Level>])", "Drills up the members of a set that are below a specified level.", "fx*") {

            public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
                throw new UnsupportedOperationException();
            }
        });
    if (false)
        builder.define(new FunDefBase("DrillupMember", "DrillupMember(<Set1>, <Set2>)", "Drills up the members in a set that are present in a second specified set.", "fx*") {

            public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
                throw new UnsupportedOperationException();
            }
        });
    builder.define(ExceptFunDef.Resolver);
    builder.define(ExistsFunDef.resolver);
    builder.define(ExtractFunDef.Resolver);
    builder.define(FilterFunDef.instance);
    builder.define(GenerateFunDef.ListResolver);
    builder.define(GenerateFunDef.StringResolver);
    builder.define(HeadTailFunDef.HeadResolver);
    builder.define(HierarchizeFunDef.Resolver);
    builder.define(IntersectFunDef.resolver);
    builder.define(LastPeriodsFunDef.Resolver);
    // <Dimension>.Members is really just shorthand for <Hierarchy>.Members
    builder.define(new FunInfo("Members", "Returns the set of members in a dimension.", "pxd"));
    // <Hierarchy>.Members
    builder.define(new FunDefBase("Members", "Returns the set of members in a hierarchy.", "pxh") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final HierarchyCalc hierarchyCalc = compiler.compileHierarchy(call.getArg(0));
            return new AbstractListCalc(call, new Calc[] { hierarchyCalc }) {

                public TupleList evaluateList(Evaluator evaluator) {
                    Hierarchy hierarchy = hierarchyCalc.evaluateHierarchy(evaluator);
                    return hierarchyMembers(hierarchy, evaluator, false);
                }
            };
        }
    });
    // <Hierarchy>.AllMembers
    builder.define(new FunDefBase("AllMembers", "Returns a set that contains all members, including calculated members, of the specified hierarchy.", "pxh") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final HierarchyCalc hierarchyCalc = compiler.compileHierarchy(call.getArg(0));
            return new AbstractListCalc(call, new Calc[] { hierarchyCalc }) {

                public TupleList evaluateList(Evaluator evaluator) {
                    Hierarchy hierarchy = hierarchyCalc.evaluateHierarchy(evaluator);
                    return hierarchyMembers(hierarchy, evaluator, true);
                }
            };
        }
    });
    // <Level>.Members
    builder.define(LevelMembersFunDef.INSTANCE);
    // <Level>.AllMembers
    builder.define(new FunDefBase("AllMembers", "Returns a set that contains all members, including calculated members, of the specified level.", "pxl") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final LevelCalc levelCalc = compiler.compileLevel(call.getArg(0));
            return new AbstractListCalc(call, new Calc[] { levelCalc }) {

                public TupleList evaluateList(Evaluator evaluator) {
                    Level level = levelCalc.evaluateLevel(evaluator);
                    return levelMembers(level, evaluator, true);
                }
            };
        }
    });
    builder.define(XtdFunDef.MtdResolver);
    builder.define(OrderFunDef.Resolver);
    builder.define(UnorderFunDef.Resolver);
    builder.define(PeriodsToDateFunDef.Resolver);
    builder.define(XtdFunDef.QtdResolver);
    // StripCalculatedMembers(<Set>)
    builder.define(new FunDefBase("StripCalculatedMembers", "Removes calculated members from a set.", "fxx") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final ListCalc listCalc = compiler.compileList(call.getArg(0));
            return new AbstractListCalc(call, new Calc[] { listCalc }) {

                public TupleList evaluateList(Evaluator evaluator) {
                    TupleList list = listCalc.evaluateList(evaluator);
                    return removeCalculatedMembers(list);
                }
            };
        }
    });
    // <Member>.Siblings
    builder.define(new FunDefBase("Siblings", "Returns the siblings of a specified member, including the member itself.", "pxm") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final MemberCalc memberCalc = compiler.compileMember(call.getArg(0));
            return new AbstractListCalc(call, new Calc[] { memberCalc }) {

                public TupleList evaluateList(Evaluator evaluator) {
                    final Member member = memberCalc.evaluateMember(evaluator);
                    return new UnaryTupleList(memberSiblings(member, evaluator));
                }
            };
        }

        List<Member> memberSiblings(Member member, Evaluator evaluator) {
            if (member.isNull()) {
                // the null member has no siblings -- not even itself
                return Collections.emptyList();
            }
            Member parent = member.getParentMember();
            final SchemaReader schemaReader = evaluator.getSchemaReader();
            if (parent == null) {
                return schemaReader.getHierarchyRootMembers(member.getHierarchy());
            } else {
                return schemaReader.getMemberChildren(parent);
            }
        }
    });
    builder.define(StrToSetFunDef.Resolver);
    builder.define(SubsetFunDef.Resolver);
    builder.define(HeadTailFunDef.TailResolver);
    builder.define(ToggleDrillStateFunDef.Resolver);
    builder.define(UnionFunDef.Resolver);
    builder.define(VisualTotalsFunDef.Resolver);
    builder.define(XtdFunDef.WtdResolver);
    builder.define(XtdFunDef.YtdResolver);
    // "<member> : <member>" operator
    builder.define(RangeFunDef.instance);
    // "{ <member> [,...] }" operator
    builder.define(SetFunDef.Resolver);
    builder.define(NativizeSetFunDef.Resolver);
    // Existing <Set>
    builder.define(ExistingFunDef.instance);
    // 
    // STRING FUNCTIONS
    builder.define(FormatFunDef.Resolver);
    // <Dimension>.Caption
    builder.define(new FunDefBase("Caption", "Returns the caption of a dimension.", "pSd") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final DimensionCalc dimensionCalc = compiler.compileDimension(call.getArg(0));
            return new AbstractStringCalc(call, new Calc[] { dimensionCalc }) {

                public String evaluateString(Evaluator evaluator) {
                    final Dimension dimension = dimensionCalc.evaluateDimension(evaluator);
                    return dimension.getCaption();
                }
            };
        }
    });
    // <Hierarchy>.Caption
    builder.define(new FunDefBase("Caption", "Returns the caption of a hierarchy.", "pSh") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final HierarchyCalc hierarchyCalc = compiler.compileHierarchy(call.getArg(0));
            return new AbstractStringCalc(call, new Calc[] { hierarchyCalc }) {

                public String evaluateString(Evaluator evaluator) {
                    final Hierarchy hierarchy = hierarchyCalc.evaluateHierarchy(evaluator);
                    return hierarchy.getCaption();
                }
            };
        }
    });
    // <Level>.Caption
    builder.define(new FunDefBase("Caption", "Returns the caption of a level.", "pSl") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final LevelCalc levelCalc = compiler.compileLevel(call.getArg(0));
            return new AbstractStringCalc(call, new Calc[] { levelCalc }) {

                public String evaluateString(Evaluator evaluator) {
                    final Level level = levelCalc.evaluateLevel(evaluator);
                    return level.getCaption();
                }
            };
        }
    });
    // <Member>.Caption
    builder.define(new FunDefBase("Caption", "Returns the caption of a member.", "pSm") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final MemberCalc memberCalc = compiler.compileMember(call.getArg(0));
            return new AbstractStringCalc(call, new Calc[] { memberCalc }) {

                public String evaluateString(Evaluator evaluator) {
                    final Member member = memberCalc.evaluateMember(evaluator);
                    return member.getCaption();
                }
            };
        }
    });
    // <Dimension>.Name
    builder.define(new FunDefBase("Name", "Returns the name of a dimension.", "pSd") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final DimensionCalc dimensionCalc = compiler.compileDimension(call.getArg(0));
            return new AbstractStringCalc(call, new Calc[] { dimensionCalc }) {

                public String evaluateString(Evaluator evaluator) {
                    final Dimension dimension = dimensionCalc.evaluateDimension(evaluator);
                    return dimension.getName();
                }
            };
        }
    });
    // <Hierarchy>.Name
    builder.define(new FunDefBase("Name", "Returns the name of a hierarchy.", "pSh") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final HierarchyCalc hierarchyCalc = compiler.compileHierarchy(call.getArg(0));
            return new AbstractStringCalc(call, new Calc[] { hierarchyCalc }) {

                public String evaluateString(Evaluator evaluator) {
                    final Hierarchy hierarchy = hierarchyCalc.evaluateHierarchy(evaluator);
                    return hierarchy.getName();
                }
            };
        }
    });
    // <Level>.Name
    builder.define(new FunDefBase("Name", "Returns the name of a level.", "pSl") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final LevelCalc levelCalc = compiler.compileLevel(call.getArg(0));
            return new AbstractStringCalc(call, new Calc[] { levelCalc }) {

                public String evaluateString(Evaluator evaluator) {
                    final Level level = levelCalc.evaluateLevel(evaluator);
                    return level.getName();
                }
            };
        }
    });
    // <Member>.Name
    builder.define(new FunDefBase("Name", "Returns the name of a member.", "pSm") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final MemberCalc memberCalc = compiler.compileMember(call.getArg(0));
            return new AbstractStringCalc(call, new Calc[] { memberCalc }) {

                public String evaluateString(Evaluator evaluator) {
                    final Member member = memberCalc.evaluateMember(evaluator);
                    return member.getName();
                }
            };
        }
    });
    builder.define(SetToStrFunDef.instance);
    builder.define(TupleToStrFunDef.instance);
    // <Dimension>.UniqueName
    builder.define(new FunDefBase("UniqueName", "Returns the unique name of a dimension.", "pSd") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final DimensionCalc dimensionCalc = compiler.compileDimension(call.getArg(0));
            return new AbstractStringCalc(call, new Calc[] { dimensionCalc }) {

                public String evaluateString(Evaluator evaluator) {
                    final Dimension dimension = dimensionCalc.evaluateDimension(evaluator);
                    return dimension.getUniqueName();
                }
            };
        }
    });
    // <Hierarchy>.UniqueName
    builder.define(new FunDefBase("UniqueName", "Returns the unique name of a hierarchy.", "pSh") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final HierarchyCalc hierarchyCalc = compiler.compileHierarchy(call.getArg(0));
            return new AbstractStringCalc(call, new Calc[] { hierarchyCalc }) {

                public String evaluateString(Evaluator evaluator) {
                    final Hierarchy hierarchy = hierarchyCalc.evaluateHierarchy(evaluator);
                    return hierarchy.getUniqueName();
                }
            };
        }
    });
    // <Level>.UniqueName
    builder.define(new FunDefBase("UniqueName", "Returns the unique name of a level.", "pSl") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final LevelCalc levelCalc = compiler.compileLevel(call.getArg(0));
            return new AbstractStringCalc(call, new Calc[] { levelCalc }) {

                public String evaluateString(Evaluator evaluator) {
                    final Level level = levelCalc.evaluateLevel(evaluator);
                    return level.getUniqueName();
                }
            };
        }
    });
    // <Member>.UniqueName
    builder.define(new FunDefBase("UniqueName", "Returns the unique name of a member.", "pSm") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final MemberCalc memberCalc = compiler.compileMember(call.getArg(0));
            return new AbstractStringCalc(call, new Calc[] { memberCalc }) {

                public String evaluateString(Evaluator evaluator) {
                    final Member member = memberCalc.evaluateMember(evaluator);
                    return member.getUniqueName();
                }
            };
        }
    });
    // <Set>.Current
    if (false)
        builder.define(new FunDefBase("Current", "Returns the current tuple from a set during an iteration.", "ptx") {

            public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
                throw new UnsupportedOperationException();
            }
        });
    builder.define(SetItemFunDef.intResolver);
    builder.define(SetItemFunDef.stringResolver);
    builder.define(TupleItemFunDef.instance);
    builder.define(StrToTupleFunDef.Resolver);
    // special resolver for "()"
    builder.define(TupleFunDef.Resolver);
    // 
    // GENERIC VALUE FUNCTIONS
    builder.define(CoalesceEmptyFunDef.Resolver);
    builder.define(CaseTestFunDef.Resolver);
    builder.define(CaseMatchFunDef.Resolver);
    builder.define(PropertiesFunDef.Resolver);
    // 
    // PARAMETER FUNCTIONS
    builder.define(new ParameterFunDef.ParameterResolver());
    builder.define(new ParameterFunDef.ParamRefResolver());
    // 
    // OPERATORS
    // <Numeric Expression> + <Numeric Expression>
    builder.define(new FunDefBase("+", "Adds two numbers.", "innn") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final DoubleCalc calc0 = compiler.compileDouble(call.getArg(0));
            final DoubleCalc calc1 = compiler.compileDouble(call.getArg(1));
            return new AbstractDoubleCalc(call, new Calc[] { calc0, calc1 }) {

                public double evaluateDouble(Evaluator evaluator) {
                    final double v0 = calc0.evaluateDouble(evaluator);
                    final double v1 = calc1.evaluateDouble(evaluator);
                    if (v0 == DoubleNull) {
                        if (v1 == DoubleNull) {
                            return DoubleNull;
                        } else {
                            return v1;
                        }
                    } else {
                        if (v1 == DoubleNull) {
                            return v0;
                        } else {
                            return v0 + v1;
                        }
                    }
                }
            };
        }
    });
    // <Numeric Expression> - <Numeric Expression>
    builder.define(new FunDefBase("-", "Subtracts two numbers.", "innn") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final DoubleCalc calc0 = compiler.compileDouble(call.getArg(0));
            final DoubleCalc calc1 = compiler.compileDouble(call.getArg(1));
            return new AbstractDoubleCalc(call, new Calc[] { calc0, calc1 }) {

                public double evaluateDouble(Evaluator evaluator) {
                    final double v0 = calc0.evaluateDouble(evaluator);
                    final double v1 = calc1.evaluateDouble(evaluator);
                    if (v0 == DoubleNull) {
                        if (v1 == DoubleNull) {
                            return DoubleNull;
                        } else {
                            return -v1;
                        }
                    } else {
                        if (v1 == DoubleNull) {
                            return v0;
                        } else {
                            return v0 - v1;
                        }
                    }
                }
            };
        }
    });
    // <Numeric Expression> * <Numeric Expression>
    builder.define(new FunDefBase("*", "Multiplies two numbers.", "innn") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final DoubleCalc calc0 = compiler.compileDouble(call.getArg(0));
            final DoubleCalc calc1 = compiler.compileDouble(call.getArg(1));
            return new AbstractDoubleCalc(call, new Calc[] { calc0, calc1 }) {

                public double evaluateDouble(Evaluator evaluator) {
                    final double v0 = calc0.evaluateDouble(evaluator);
                    final double v1 = calc1.evaluateDouble(evaluator);
                    // null.
                    if (v0 == DoubleNull || v1 == DoubleNull) {
                        return DoubleNull;
                    } else {
                        return v0 * v1;
                    }
                }
            };
        }
    });
    // <Numeric Expression> / <Numeric Expression>
    builder.define(new FunDefBase("/", "Divides two numbers.", "innn") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final DoubleCalc calc0 = compiler.compileDouble(call.getArg(0));
            final DoubleCalc calc1 = compiler.compileDouble(call.getArg(1));
            final boolean isNullDenominatorProducesNull = MondrianProperties.instance().NullDenominatorProducesNull.get();
            // conform to MSAS behavior.
            if (!isNullDenominatorProducesNull) {
                return new AbstractDoubleCalc(call, new Calc[] { calc0, calc1 }) {

                    public double evaluateDouble(Evaluator evaluator) {
                        final double v0 = calc0.evaluateDouble(evaluator);
                        final double v1 = calc1.evaluateDouble(evaluator);
                        // 
                        if (v0 == DoubleNull) {
                            return DoubleNull;
                        } else if (v1 == DoubleNull) {
                            // Null only in denominator returns Infinity.
                            return Double.POSITIVE_INFINITY;
                        } else {
                            return v0 / v1;
                        }
                    }
                };
            } else {
                return new AbstractDoubleCalc(call, new Calc[] { calc0, calc1 }) {

                    public double evaluateDouble(Evaluator evaluator) {
                        final double v0 = calc0.evaluateDouble(evaluator);
                        final double v1 = calc1.evaluateDouble(evaluator);
                        // DoubleNull.
                        if (v0 == DoubleNull || v1 == DoubleNull) {
                            return DoubleNull;
                        } else {
                            return v0 / v1;
                        }
                    }
                };
            }
        }
    });
    // - <Numeric Expression>
    builder.define(new FunDefBase("-", "Returns the negative of a number.", "Pnn") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final DoubleCalc calc = compiler.compileDouble(call.getArg(0));
            return new AbstractDoubleCalc(call, new Calc[] { calc }) {

                public double evaluateDouble(Evaluator evaluator) {
                    final double v = calc.evaluateDouble(evaluator);
                    if (v == DoubleNull) {
                        return DoubleNull;
                    } else {
                        return -v;
                    }
                }
            };
        }
    });
    // <String Expression> || <String Expression>
    builder.define(new FunDefBase("||", "Concatenates two strings.", "iSSS") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final StringCalc calc0 = compiler.compileString(call.getArg(0));
            final StringCalc calc1 = compiler.compileString(call.getArg(1));
            return new AbstractStringCalc(call, new Calc[] { calc0, calc1 }) {

                public String evaluateString(Evaluator evaluator) {
                    final String s0 = calc0.evaluateString(evaluator);
                    final String s1 = calc1.evaluateString(evaluator);
                    return s0 + s1;
                }
            };
        }
    });
    // <Logical Expression> AND <Logical Expression>
    builder.define(new FunDefBase("AND", "Returns the conjunction of two conditions.", "ibbb") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final BooleanCalc calc0 = compiler.compileBoolean(call.getArg(0));
            final BooleanCalc calc1 = compiler.compileBoolean(call.getArg(1));
            return new AbstractBooleanCalc(call, new Calc[] { calc0, calc1 }) {

                public boolean evaluateBoolean(Evaluator evaluator) {
                    boolean b0 = calc0.evaluateBoolean(evaluator);
                    // referenced in the AND expression in a single query
                    if (!evaluator.isEvalAxes() && !b0) {
                        return false;
                    }
                    boolean b1 = calc1.evaluateBoolean(evaluator);
                    return b0 && b1;
                }
            };
        }
    });
    // <Logical Expression> OR <Logical Expression>
    builder.define(new FunDefBase("OR", "Returns the disjunction of two conditions.", "ibbb") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final BooleanCalc calc0 = compiler.compileBoolean(call.getArg(0));
            final BooleanCalc calc1 = compiler.compileBoolean(call.getArg(1));
            return new AbstractBooleanCalc(call, new Calc[] { calc0, calc1 }) {

                public boolean evaluateBoolean(Evaluator evaluator) {
                    boolean b0 = calc0.evaluateBoolean(evaluator);
                    // referenced in the OR expression in a single query
                    if (!evaluator.isEvalAxes() && b0) {
                        return true;
                    }
                    boolean b1 = calc1.evaluateBoolean(evaluator);
                    return b0 || b1;
                }
            };
        }
    });
    // <Logical Expression> XOR <Logical Expression>
    builder.define(new FunDefBase("XOR", "Returns whether two conditions are mutually exclusive.", "ibbb") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final BooleanCalc calc0 = compiler.compileBoolean(call.getArg(0));
            final BooleanCalc calc1 = compiler.compileBoolean(call.getArg(1));
            return new AbstractBooleanCalc(call, new Calc[] { calc0, calc1 }) {

                public boolean evaluateBoolean(Evaluator evaluator) {
                    final boolean b0 = calc0.evaluateBoolean(evaluator);
                    final boolean b1 = calc1.evaluateBoolean(evaluator);
                    return b0 != b1;
                }
            };
        }
    });
    // NOT <Logical Expression>
    builder.define(new FunDefBase("NOT", "Returns the negation of a condition.", "Pbb") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final BooleanCalc calc = compiler.compileBoolean(call.getArg(0));
            return new AbstractBooleanCalc(call, new Calc[] { calc }) {

                public boolean evaluateBoolean(Evaluator evaluator) {
                    return !calc.evaluateBoolean(evaluator);
                }
            };
        }
    });
    // <String Expression> = <String Expression>
    builder.define(new FunDefBase("=", "Returns whether two expressions are equal.", "ibSS") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final StringCalc calc0 = compiler.compileString(call.getArg(0));
            final StringCalc calc1 = compiler.compileString(call.getArg(1));
            return new AbstractBooleanCalc(call, new Calc[] { calc0, calc1 }) {

                public boolean evaluateBoolean(Evaluator evaluator) {
                    final String b0 = calc0.evaluateString(evaluator);
                    final String b1 = calc1.evaluateString(evaluator);
                    if (b0 == null || b1 == null) {
                        return BooleanNull;
                    }
                    return b0.equals(b1);
                }
            };
        }
    });
    // <Numeric Expression> = <Numeric Expression>
    builder.define(new FunDefBase("=", "Returns whether two expressions are equal.", "ibnn") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final DoubleCalc calc0 = compiler.compileDouble(call.getArg(0));
            final DoubleCalc calc1 = compiler.compileDouble(call.getArg(1));
            return new AbstractBooleanCalc(call, new Calc[] { calc0, calc1 }) {

                public boolean evaluateBoolean(Evaluator evaluator) {
                    final double v0 = calc0.evaluateDouble(evaluator);
                    final double v1 = calc1.evaluateDouble(evaluator);
                    if (Double.isNaN(v0) || Double.isNaN(v1) || v0 == DoubleNull || v1 == DoubleNull) {
                        return BooleanNull;
                    }
                    return v0 == v1;
                }
            };
        }
    });
    // <String Expression> <> <String Expression>
    builder.define(new FunDefBase("<>", "Returns whether two expressions are not equal.", "ibSS") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final StringCalc calc0 = compiler.compileString(call.getArg(0));
            final StringCalc calc1 = compiler.compileString(call.getArg(1));
            return new AbstractBooleanCalc(call, new Calc[] { calc0, calc1 }) {

                public boolean evaluateBoolean(Evaluator evaluator) {
                    final String b0 = calc0.evaluateString(evaluator);
                    final String b1 = calc1.evaluateString(evaluator);
                    if (b0 == null || b1 == null) {
                        return BooleanNull;
                    }
                    return !b0.equals(b1);
                }
            };
        }
    });
    // <Numeric Expression> <> <Numeric Expression>
    builder.define(new FunDefBase("<>", "Returns whether two expressions are not equal.", "ibnn") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final DoubleCalc calc0 = compiler.compileDouble(call.getArg(0));
            final DoubleCalc calc1 = compiler.compileDouble(call.getArg(1));
            return new AbstractBooleanCalc(call, new Calc[] { calc0, calc1 }) {

                public boolean evaluateBoolean(Evaluator evaluator) {
                    final double v0 = calc0.evaluateDouble(evaluator);
                    final double v1 = calc1.evaluateDouble(evaluator);
                    if (Double.isNaN(v0) || Double.isNaN(v1) || v0 == DoubleNull || v1 == DoubleNull) {
                        return BooleanNull;
                    }
                    return v0 != v1;
                }
            };
        }
    });
    // <Numeric Expression> < <Numeric Expression>
    builder.define(new FunDefBase("<", "Returns whether an expression is less than another.", "ibnn") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final DoubleCalc calc0 = compiler.compileDouble(call.getArg(0));
            final DoubleCalc calc1 = compiler.compileDouble(call.getArg(1));
            return new AbstractBooleanCalc(call, new Calc[] { calc0, calc1 }) {

                public boolean evaluateBoolean(Evaluator evaluator) {
                    final double v0 = calc0.evaluateDouble(evaluator);
                    final double v1 = calc1.evaluateDouble(evaluator);
                    if (Double.isNaN(v0) || Double.isNaN(v1) || v0 == DoubleNull || v1 == DoubleNull) {
                        return BooleanNull;
                    }
                    return v0 < v1;
                }
            };
        }
    });
    // <String Expression> < <String Expression>
    builder.define(new FunDefBase("<", "Returns whether an expression is less than another.", "ibSS") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final StringCalc calc0 = compiler.compileString(call.getArg(0));
            final StringCalc calc1 = compiler.compileString(call.getArg(1));
            return new AbstractBooleanCalc(call, new Calc[] { calc0, calc1 }) {

                public boolean evaluateBoolean(Evaluator evaluator) {
                    final String b0 = calc0.evaluateString(evaluator);
                    final String b1 = calc1.evaluateString(evaluator);
                    if (b0 == null || b1 == null) {
                        return BooleanNull;
                    }
                    return b0.compareTo(b1) < 0;
                }
            };
        }
    });
    // <Numeric Expression> <= <Numeric Expression>
    builder.define(new FunDefBase("<=", "Returns whether an expression is less than or equal to another.", "ibnn") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final DoubleCalc calc0 = compiler.compileDouble(call.getArg(0));
            final DoubleCalc calc1 = compiler.compileDouble(call.getArg(1));
            return new AbstractBooleanCalc(call, new Calc[] { calc0, calc1 }) {

                public boolean evaluateBoolean(Evaluator evaluator) {
                    final double v0 = calc0.evaluateDouble(evaluator);
                    final double v1 = calc1.evaluateDouble(evaluator);
                    if (Double.isNaN(v0) || Double.isNaN(v1) || v0 == DoubleNull || v1 == DoubleNull) {
                        return BooleanNull;
                    }
                    return v0 <= v1;
                }
            };
        }
    });
    // <String Expression> <= <String Expression>
    builder.define(new FunDefBase("<=", "Returns whether an expression is less than or equal to another.", "ibSS") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final StringCalc calc0 = compiler.compileString(call.getArg(0));
            final StringCalc calc1 = compiler.compileString(call.getArg(1));
            return new AbstractBooleanCalc(call, new Calc[] { calc0, calc1 }) {

                public boolean evaluateBoolean(Evaluator evaluator) {
                    final String b0 = calc0.evaluateString(evaluator);
                    final String b1 = calc1.evaluateString(evaluator);
                    if (b0 == null || b1 == null) {
                        return BooleanNull;
                    }
                    return b0.compareTo(b1) <= 0;
                }
            };
        }
    });
    // <Numeric Expression> > <Numeric Expression>
    builder.define(new FunDefBase(">", "Returns whether an expression is greater than another.", "ibnn") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final DoubleCalc calc0 = compiler.compileDouble(call.getArg(0));
            final DoubleCalc calc1 = compiler.compileDouble(call.getArg(1));
            return new AbstractBooleanCalc(call, new Calc[] { calc0, calc1 }) {

                public boolean evaluateBoolean(Evaluator evaluator) {
                    final double v0 = calc0.evaluateDouble(evaluator);
                    final double v1 = calc1.evaluateDouble(evaluator);
                    if (Double.isNaN(v0) || Double.isNaN(v1) || v0 == DoubleNull || v1 == DoubleNull) {
                        return BooleanNull;
                    }
                    return v0 > v1;
                }
            };
        }
    });
    // <String Expression> > <String Expression>
    builder.define(new FunDefBase(">", "Returns whether an expression is greater than another.", "ibSS") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final StringCalc calc0 = compiler.compileString(call.getArg(0));
            final StringCalc calc1 = compiler.compileString(call.getArg(1));
            return new AbstractBooleanCalc(call, new Calc[] { calc0, calc1 }) {

                public boolean evaluateBoolean(Evaluator evaluator) {
                    final String b0 = calc0.evaluateString(evaluator);
                    final String b1 = calc1.evaluateString(evaluator);
                    if (b0 == null || b1 == null) {
                        return BooleanNull;
                    }
                    return b0.compareTo(b1) > 0;
                }
            };
        }
    });
    // <Numeric Expression> >= <Numeric Expression>
    builder.define(new FunDefBase(">=", "Returns whether an expression is greater than or equal to another.", "ibnn") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final DoubleCalc calc0 = compiler.compileDouble(call.getArg(0));
            final DoubleCalc calc1 = compiler.compileDouble(call.getArg(1));
            return new AbstractBooleanCalc(call, new Calc[] { calc0, calc1 }) {

                public boolean evaluateBoolean(Evaluator evaluator) {
                    final double v0 = calc0.evaluateDouble(evaluator);
                    final double v1 = calc1.evaluateDouble(evaluator);
                    if (Double.isNaN(v0) || Double.isNaN(v1) || v0 == DoubleNull || v1 == DoubleNull) {
                        return BooleanNull;
                    }
                    return v0 >= v1;
                }
            };
        }
    });
    // <String Expression> >= <String Expression>
    builder.define(new FunDefBase(">=", "Returns whether an expression is greater than or equal to another.", "ibSS") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final StringCalc calc0 = compiler.compileString(call.getArg(0));
            final StringCalc calc1 = compiler.compileString(call.getArg(1));
            return new AbstractBooleanCalc(call, new Calc[] { calc0, calc1 }) {

                public boolean evaluateBoolean(Evaluator evaluator) {
                    final String b0 = calc0.evaluateString(evaluator);
                    final String b1 = calc1.evaluateString(evaluator);
                    if (b0 == null || b1 == null) {
                        return BooleanNull;
                    }
                    return b0.compareTo(b1) >= 0;
                }
            };
        }
    });
    // NON-STANDARD FUNCTIONS
    builder.define(NthQuartileFunDef.FirstQResolver);
    builder.define(NthQuartileFunDef.ThirdQResolver);
    builder.define(CalculatedChildFunDef.instance);
    builder.define(CachedExistsFunDef.instance);
    builder.define(CastFunDef.Resolver);
    // UCase(<String Expression>)
    builder.define(new FunDefBase("UCase", "Returns a string that has been converted to uppercase", "fSS") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final Locale locale = compiler.getEvaluator().getConnectionLocale();
            final StringCalc stringCalc = compiler.compileString(call.getArg(0));
            if (stringCalc.getType().getClass().equals(NullType.class)) {
                throw newEvalException(this, "No method with the signature UCase(NULL) matches known functions.");
            }
            return new AbstractStringCalc(call, new Calc[] { stringCalc }) {

                public String evaluateString(Evaluator evaluator) {
                    String value = stringCalc.evaluateString(evaluator);
                    return value.toUpperCase(locale);
                }
            };
        }
    });
    // Len(<String Expression>)
    builder.define(new FunDefBase("Len", "Returns the number of characters in a string", "fnS") {

        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
            final StringCalc stringCalc = compiler.compileString(call.getArg(0));
            return new AbstractIntegerCalc(call, new Calc[] { stringCalc }) {

                public int evaluateInteger(Evaluator evaluator) {
                    String value = stringCalc.evaluateString(evaluator);
                    if (value == null) {
                        return 0;
                    }
                    return value.length();
                }
            };
        }
    });
    // Define VBA functions.
    for (FunDef funDef : JavaFunDef.scan(Vba.class)) {
        builder.define(funDef);
    }
    // Define Excel functions.
    for (FunDef funDef : JavaFunDef.scan(Excel.class)) {
        builder.define(funDef);
    }
}
Also used : ValueCalc(mondrian.calc.impl.ValueCalc) Locale(java.util.Locale) Hierarchy(mondrian.olap.Hierarchy) AbstractIntegerCalc(mondrian.calc.impl.AbstractIntegerCalc) IntegerCalc(mondrian.calc.IntegerCalc) AbstractBooleanCalc(mondrian.calc.impl.AbstractBooleanCalc) List(java.util.List) ArrayList(java.util.ArrayList) UnaryTupleList(mondrian.calc.impl.UnaryTupleList) TupleList(mondrian.calc.TupleList) ExpCompiler(mondrian.calc.ExpCompiler) Member(mondrian.olap.Member) AbstractStringCalc(mondrian.calc.impl.AbstractStringCalc) StringCalc(mondrian.calc.StringCalc) AbstractStringCalc(mondrian.calc.impl.AbstractStringCalc) DimensionCalc(mondrian.calc.DimensionCalc) HierarchyCalc(mondrian.calc.HierarchyCalc) FunDef(mondrian.olap.FunDef) CalculatedChildFunDef(mondrian.olap.fun.extra.CalculatedChildFunDef) NthQuartileFunDef(mondrian.olap.fun.extra.NthQuartileFunDef) CachedExistsFunDef(mondrian.olap.fun.extra.CachedExistsFunDef) AbstractListCalc(mondrian.calc.impl.AbstractListCalc) ListCalc(mondrian.calc.ListCalc) Level(mondrian.olap.Level) NullType(mondrian.olap.type.NullType) SchemaReader(mondrian.olap.SchemaReader) GenericCalc(mondrian.calc.impl.GenericCalc) AbstractListCalc(mondrian.calc.impl.AbstractListCalc) AbstractLevelCalc(mondrian.calc.impl.AbstractLevelCalc) UnaryTupleList(mondrian.calc.impl.UnaryTupleList) AbstractDoubleCalc(mondrian.calc.impl.AbstractDoubleCalc) DoubleCalc(mondrian.calc.DoubleCalc) AbstractDoubleCalc(mondrian.calc.impl.AbstractDoubleCalc) PrintWriter(java.io.PrintWriter) Aggregator(mondrian.olap.Aggregator) AbstractDoubleCalc(mondrian.calc.impl.AbstractDoubleCalc) Calc(mondrian.calc.Calc) AbstractStringCalc(mondrian.calc.impl.AbstractStringCalc) AbstractBooleanCalc(mondrian.calc.impl.AbstractBooleanCalc) StringCalc(mondrian.calc.StringCalc) AbstractListCalc(mondrian.calc.impl.AbstractListCalc) ListCalc(mondrian.calc.ListCalc) HierarchyCalc(mondrian.calc.HierarchyCalc) GenericCalc(mondrian.calc.impl.GenericCalc) ValueCalc(mondrian.calc.impl.ValueCalc) AbstractIntegerCalc(mondrian.calc.impl.AbstractIntegerCalc) DimensionCalc(mondrian.calc.DimensionCalc) DoubleCalc(mondrian.calc.DoubleCalc) BooleanCalc(mondrian.calc.BooleanCalc) LevelCalc(mondrian.calc.LevelCalc) MemberCalc(mondrian.calc.MemberCalc) IntegerCalc(mondrian.calc.IntegerCalc) AbstractMemberCalc(mondrian.calc.impl.AbstractMemberCalc) AbstractLevelCalc(mondrian.calc.impl.AbstractLevelCalc) AbstractMemberCalc(mondrian.calc.impl.AbstractMemberCalc) LevelCalc(mondrian.calc.LevelCalc) AbstractLevelCalc(mondrian.calc.impl.AbstractLevelCalc) Dimension(mondrian.olap.Dimension) Evaluator(mondrian.olap.Evaluator) OlapElement(mondrian.olap.OlapElement) UnaryTupleList(mondrian.calc.impl.UnaryTupleList) TupleList(mondrian.calc.TupleList) LevelType(mondrian.olap.type.LevelType) NullType(mondrian.olap.type.NullType) Type(mondrian.olap.type.Type) Cube(mondrian.olap.Cube) MemberCalc(mondrian.calc.MemberCalc) AbstractMemberCalc(mondrian.calc.impl.AbstractMemberCalc) ResolvedFunCall(mondrian.mdx.ResolvedFunCall) Exp(mondrian.olap.Exp) AbstractIntegerCalc(mondrian.calc.impl.AbstractIntegerCalc) Validator(mondrian.olap.Validator) AbstractBooleanCalc(mondrian.calc.impl.AbstractBooleanCalc) BooleanCalc(mondrian.calc.BooleanCalc)

Aggregations

PrintWriter (java.io.PrintWriter)1 ArrayList (java.util.ArrayList)1 List (java.util.List)1 Locale (java.util.Locale)1 BooleanCalc (mondrian.calc.BooleanCalc)1 Calc (mondrian.calc.Calc)1 DimensionCalc (mondrian.calc.DimensionCalc)1 DoubleCalc (mondrian.calc.DoubleCalc)1 ExpCompiler (mondrian.calc.ExpCompiler)1 HierarchyCalc (mondrian.calc.HierarchyCalc)1 IntegerCalc (mondrian.calc.IntegerCalc)1 LevelCalc (mondrian.calc.LevelCalc)1 ListCalc (mondrian.calc.ListCalc)1 MemberCalc (mondrian.calc.MemberCalc)1 StringCalc (mondrian.calc.StringCalc)1 TupleList (mondrian.calc.TupleList)1 AbstractBooleanCalc (mondrian.calc.impl.AbstractBooleanCalc)1 AbstractDoubleCalc (mondrian.calc.impl.AbstractDoubleCalc)1 AbstractIntegerCalc (mondrian.calc.impl.AbstractIntegerCalc)1 AbstractLevelCalc (mondrian.calc.impl.AbstractLevelCalc)1