001/*
002// This software is subject to the terms of the Eclipse Public License v1.0
003// Agreement, available at the following URL:
004// http://www.eclipse.org/legal/epl-v10.html.
005// You must accept the terms of that agreement to use this software.
006//
007// Copyright (C) 2002-2005 Julian Hyde
008// Copyright (C) 2005-2009 Pentaho and others
009// All Rights Reserved.
010*/
011package mondrian.olap.fun;
012
013import mondrian.calc.Calc;
014import mondrian.calc.ExpCompiler;
015import mondrian.mdx.ResolvedFunCall;
016import mondrian.olap.*;
017import mondrian.olap.type.*;
018import mondrian.olap.type.DimensionType;
019import mondrian.olap.type.LevelType;
020
021import java.io.PrintWriter;
022
023/**
024 * <code>FunDefBase</code> is the default implementation of {@link FunDef}.
025 *
026 * <h3>Signatures</h3>
027 *
028 * <p>A function is defined by the following:</p>
029 *
030 * <table border="1">
031 * <tr><th>Parameter</th><th>Meaning</th><th>Example</th></tr>
032 * <tr>
033 * <td>name</td><td>Name of the function</td><td>"Members"</td>
034 * </tr>
035 * <tr>
036 * <td>signature</td>
037 * <td>Signature of the function</td>
038 * <td>"&lt;Dimension&gt;.Members"</td>
039 * </tr>
040 * <tr>
041 * <td>description</td>
042 * <td>Description of the function</td>
043 * <td>"Returns the set of all members in a dimension."</td>
044 * </tr>
045 * <tr>
046 * <td>flags</td>
047 * <td>Encoding of the syntactic type, return type, and parameter
048 * types of this operator. The encoding is described below.</td>
049 * <td>"pxd"</tr>
050 * </table>
051 *
052 * The <code>flags</code> field is an string which encodes
053 * the syntactic type, return type, and parameter types of this operator.
054 * <ul>
055 * <li>The first character determines the syntactic type, as described by
056 * {@link FunUtil#decodeSyntacticType(String)}.
057 * <li>The second character determines the return type, as described by
058 * {@link FunUtil#decodeReturnCategory(String)}.
059 * <li>The third and subsequence characters determine the types of the
060 * arguments arguments, as described by
061 * {@link FunUtil#decodeParameterCategories(String)}.
062 * </ul><p/>
063 *
064 * For example,  <code>"pxd"</code> means "an operator with
065 * {@link Syntax#Property property} syntax (p) which returns a set
066 * (x) and takes a dimension (d) as its argument".<p/>
067 *
068 * The arguments are always read from left to right, regardless of the
069 * syntactic type of the operator. For example, the
070 * <code>"&lt;Set&gt;.Item(&lt;Index&gt;)"</code> operator
071 * (signature <code>"mmxn"</code>) has the
072 * syntax of a method-call, and takes two parameters:
073 * a set (x) and a numeric (n).<p/>
074 *
075 * @author jhyde
076 * @since 26 February, 2002
077 */
078public abstract class FunDefBase extends FunUtil implements FunDef {
079    protected final int flags;
080    private final String name;
081    final String signature;
082    private final String description;
083    protected final int returnCategory;
084    protected final int[] parameterCategories;
085
086    /**
087     * Creates an operator.
088     *
089     * @param name           Name of the function, for example "Members".
090     * @param signature      Signature of the function, for example
091     *                       "&lt;Dimension&gt;.Members".
092     * @param description    Description of the function, for example
093     *                       "Returns the set of all members in a dimension."
094     * @param syntax         Syntactic type of the operator (for
095     *                       example, function, method, infix operator)
096     * @param returnCategory The {@link Category} of the value returned by this
097     *                       operator.
098     * @param parameterCategories An array of {@link Category} codes, one for
099     *                       each parameter.
100     */
101    FunDefBase(
102        String name,
103        String signature,
104        String description,
105        Syntax syntax,
106        int returnCategory,
107        int[] parameterCategories)
108    {
109        assert name != null;
110        assert syntax != null;
111        this.name = name;
112        this.signature = signature;
113        this.description = description;
114        this.flags = syntax.ordinal();
115        this.returnCategory = returnCategory;
116        this.parameterCategories = parameterCategories;
117    }
118
119    /**
120     * Creates an operator.
121     *
122     * @param name        Name of the function, for example "Members".
123     * @param description Description of the function, for example
124     *                    "Returns the set of all members in a dimension."
125     * @param flags       Encoding of the syntactic type, return type,
126     *                    and parameter types of this operator. The
127     *                    "Members" operator has a syntactic type
128     *                    "pxd" which means "an operator with
129     *                    {@link Syntax#Property property} syntax (p) which
130     *                    returns a set (x) and takes a dimension (d) as its
131     *                    argument".
132     *                    See {@link FunUtil#decodeSyntacticType(String)},
133     *                    {@link FunUtil#decodeReturnCategory(String)},
134     *                    {@link FunUtil#decodeParameterCategories(String)}.
135     */
136    protected FunDefBase(
137        String name,
138        String description,
139        String flags)
140    {
141        this(
142            name,
143            null,
144            description,
145            decodeSyntacticType(flags),
146            decodeReturnCategory(flags),
147            decodeParameterCategories(flags));
148    }
149
150    /**
151     * Creates an operator with an explicit signature.
152     *
153     * <p>In most cases, the signature can be generated automatically, and
154     * you should use the constructor which creates an implicit signature,
155     * {@link #FunDefBase(String, String, String, String)}
156     * instead.
157     *
158     * @param name        Name of the function, for example "Members".
159     * @param signature   Signature of the function, for example
160     *                    "&lt;Dimension&gt;.Members".
161     * @param description Description of the function, for example
162     *                    "Returns the set of all members in a dimension."
163     * @param flags       Encoding of the syntactic type, return type, and
164     *                    parameter types of this operator. The "Members"
165     *                    operator has a syntactic type "pxd" which means "an
166     *                    operator with {@link Syntax#Property property} syntax
167     *                    (p) which returns a set (x) and takes a dimension (d)
168     *                    as its argument".  See
169     *                    {@link FunUtil#decodeSyntacticType(String)},
170     *                    {@link FunUtil#decodeReturnCategory(String)},
171     *                    {@link FunUtil#decodeParameterCategories(String)}.
172     */
173    protected FunDefBase(
174        String name,
175        String signature,
176        String description,
177        String flags)
178    {
179        this(
180            name,
181            signature,
182            description,
183            decodeSyntacticType(flags),
184            decodeReturnCategory(flags),
185            decodeParameterCategories(flags));
186    }
187
188    /**
189     * Convenience constructor when we are created by a {@link Resolver}.
190     *
191     * @param resolver Resolver
192     * @param returnType Return type
193     * @param parameterTypes Parameter types
194     */
195    FunDefBase(Resolver resolver, int returnType, int[] parameterTypes) {
196        this(
197            resolver.getName(),
198            null,
199            null,
200            resolver.getSyntax(),
201            returnType,
202            parameterTypes);
203    }
204
205    /**
206     * Copy constructor.
207     *
208     * @param funDef Function definition to copy
209     */
210    FunDefBase(FunDef funDef) {
211        this(
212            funDef.getName(), funDef.getSignature(),
213            funDef.getDescription(), funDef.getSyntax(),
214            funDef.getReturnCategory(), funDef.getParameterCategories());
215    }
216
217    public String getName() {
218        return name;
219    }
220
221    public String getDescription() {
222        return description;
223    }
224
225    public Syntax getSyntax() {
226        return Syntax.class.getEnumConstants()[flags];
227    }
228
229    public int getReturnCategory() {
230        return returnCategory;
231    }
232
233    public int[] getParameterCategories() {
234        return parameterCategories;
235    }
236
237    public Exp createCall(Validator validator, Exp[] args) {
238        int[] categories = getParameterCategories();
239        Util.assertTrue(categories.length == args.length);
240        for (int i = 0; i < args.length; i++) {
241            args[i] = validateArg(validator, args, i, categories[i]);
242        }
243        final Type type = getResultType(validator, args);
244        if (type == null) {
245            throw Util.newInternal("could not derive type");
246        }
247        return new ResolvedFunCall(this, args, type);
248    }
249
250    /**
251     * Validates an argument to a call to this function.
252     *
253     * <p>The default implementation of this method adds an implicit
254     * conversion to the correct type. Derived classes may override.
255     *
256     * @param validator Validator
257     * @param args Arguments to this function
258     * @param i Ordinal of argument
259     * @param category Expected {@link Category category} of argument
260     * @return Validated argument
261     */
262    protected Exp validateArg(
263        Validator validator,
264        Exp[] args,
265        int i,
266        int category)
267    {
268        return args[i];
269    }
270
271    /**
272     * Converts a type to a different category, maintaining as much type
273     * information as possible.
274     *
275     * For example, given <code>LevelType(dimension=Time, hierarchy=unknown,
276     * level=unkown)</code> and category=Hierarchy, returns
277     * <code>HierarchyType(dimension=Time)</code>.
278     *
279     * @param type Type
280     * @param category Desired category
281     * @return Type after conversion to desired category
282     */
283    static Type castType(Type type, int category) {
284        switch (category) {
285        case Category.Logical:
286            return new BooleanType();
287        case Category.Numeric:
288            return new NumericType();
289        case Category.Numeric | Category.Integer:
290            return new DecimalType(Integer.MAX_VALUE, 0);
291        case Category.String:
292            return new StringType();
293        case Category.DateTime:
294            return new DateTimeType();
295        case Category.Symbol:
296            return new SymbolType();
297        case Category.Value:
298            return new ScalarType();
299        case Category.Cube:
300            if (type instanceof Cube) {
301                return new CubeType((Cube) type);
302            }
303            return null;
304        case Category.Dimension:
305            if (type != null) {
306                return DimensionType.forType(type);
307            }
308            return null;
309        case Category.Hierarchy:
310            if (type != null) {
311                return HierarchyType.forType(type);
312            }
313            return null;
314        case Category.Level:
315            if (type != null) {
316                return LevelType.forType(type);
317            }
318            return null;
319        case Category.Member:
320            if (type != null) {
321                final MemberType memberType = TypeUtil.toMemberType(type);
322                if (memberType != null) {
323                    return memberType;
324                }
325            }
326            // Take a wild guess.
327            return MemberType.Unknown;
328        case Category.Tuple:
329            if (type != null) {
330                final Type memberType = TypeUtil.toMemberOrTupleType(type);
331                if (memberType != null) {
332                    return memberType;
333                }
334            }
335            return null;
336        case Category.Set:
337            if (type != null) {
338                final Type memberType = TypeUtil.toMemberOrTupleType(type);
339                if (memberType != null) {
340                    return new SetType(memberType);
341                }
342            }
343            return null;
344        case Category.Empty:
345            return new EmptyType();
346        default:
347            throw Category.instance.badValue(category);
348        }
349    }
350
351    /**
352     * Returns the type of a call to this function with a given set of
353     * arguments.<p/>
354     *
355     * The default implementation makes the coarse assumption that the return
356     * type is in some way related to the type of the first argument.
357     * Operators whose arguments don't follow the requirements of this
358     * implementation should override this method.<p/>
359     *
360     * If the function definition says it returns a literal type (numeric,
361     * string, symbol) then it's a fair guess that the function call
362     * returns the same kind of value.<p/>
363     *
364     * If the function definition says it returns an object type (cube,
365     * dimension, hierarchy, level, member) then we check the first
366     * argument of the function. Suppose that the function definition says
367     * that it returns a hierarchy, and the first argument of the function
368     * happens to be a member. Then it's reasonable to assume that this
369     * function returns a member.
370     *
371     * @param validator Validator
372     * @param args Arguments to the call to this operator
373     * @return result type of a call this function
374     */
375    public Type getResultType(Validator validator, Exp[] args) {
376        Type firstArgType =
377            args.length > 0
378            ? args[0].getType()
379            : null;
380        Type type = castType(firstArgType, getReturnCategory());
381        if (type != null) {
382            return type;
383        }
384        throw Util.newInternal(
385            "Cannot deduce type of call to function '" + this.name + "'");
386    }
387
388    public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
389        throw Util.newInternal(
390            "function '" + getSignature()
391            + "' has not been implemented");
392    }
393
394    public String getSignature() {
395        return getSyntax().getSignature(
396            getName(),
397            getReturnCategory(),
398            getParameterCategories());
399    }
400
401    public void unparse(Exp[] args, PrintWriter pw) {
402        getSyntax().unparse(getName(), args, pw);
403    }
404}
405
406// End FunDefBase.java