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) 2003-2005 Julian Hyde
008// Copyright (C) 2005-2009 Pentaho
009// All Rights Reserved.
010*/
011package mondrian.olap;
012
013import java.io.PrintWriter;
014
015/**
016 * Enumerated values describing the syntax of an expression.
017 *
018 * @author jhyde
019 * @since 21 July, 2003
020 */
021public enum Syntax {
022    /**
023     * Defines syntax for expression invoked <code>FUNCTION()</code> or
024     * <code>FUNCTION(args)</code>.
025     */
026    Function {
027        public void unparse(String fun, Exp[] args, PrintWriter pw) {
028            ExpBase.unparseList(pw, args, fun + "(", ", ", ")");
029        }
030    },
031
032    /**
033     * Defines syntax for expression invoked as <code>object.PROPERTY</code>.
034     */
035    Property {
036        public void unparse(String fun, Exp[] args, PrintWriter pw) {
037            Util.assertTrue(args.length >= 1);
038            args[0].unparse(pw); // 'this'
039            pw.print(".");
040            pw.print(fun);
041        }
042
043        public String getSignature(
044            String name, int returnType, int[] argTypes)
045        {
046            // e.g. "<Set>.Current"
047            return getTypeDescription(argTypes[0]) + "." + name;
048        }
049    },
050
051    /**
052     * Defines syntax for expression invoked invoked as
053     * <code>object.METHOD()</code> or
054     * <code>object.METHOD(args)</code>.
055     */
056    Method {
057        public void unparse(String fun, Exp[] args, PrintWriter pw) {
058            Util.assertTrue(args.length >= 1);
059            args[0].unparse(pw); // 'this'
060            pw.print(".");
061            pw.print(fun);
062            pw.print("(");
063            for (int i = 1; i < args.length; i++) {
064                if (i > 1) {
065                    pw.print(", ");
066                }
067                args[i].unparse(pw);
068            }
069            pw.print(")");
070        }
071
072        public String getSignature(String name, int returnType, int[] argTypes)
073        {
074            // e.g. "<Member>.Lead(<Numeric Expression>)"
075            return (returnType == Category.Unknown
076                    ? ""
077                    : getTypeDescription(returnType) + " ")
078                + getTypeDescription(argTypes[0]) + "."
079                + name + "(" + getTypeDescriptionCommaList(argTypes, 1)
080                + ")";
081        }
082    },
083
084    /**
085     * Defines syntax for expression invoked as <code>arg OPERATOR arg</code>
086     * (like '+' or 'AND').
087     */
088    Infix {
089        public void unparse(String fun, Exp[] args, PrintWriter pw) {
090            if (needParen(args)) {
091                ExpBase.unparseList(pw, args, "(", " " + fun + " ", ")");
092            } else {
093                ExpBase.unparseList(pw, args, "", " " + fun + " ", "");
094            }
095        }
096
097        public String getSignature(String name, int returnType, int[] argTypes)
098        {
099            // e.g. "<Numeric Expression> / <Numeric Expression>"
100            return getTypeDescription(argTypes[0]) + " " + name + " "
101                + getTypeDescription(argTypes[1]);
102        }
103    },
104
105    /**
106     * Defines syntax for expression invoked as <code>OPERATOR arg</code>
107     * (like unary '-').
108     */
109    Prefix {
110        public void unparse(String fun, Exp[] args, PrintWriter pw) {
111            if (needParen(args)) {
112                ExpBase.unparseList(pw, args, "(" + fun + " ", null, ")");
113            } else {
114                ExpBase.unparseList(pw, args, fun + " ", null, "");
115            }
116        }
117
118        public String getSignature(String name, int returnType, int[] argTypes)
119        {
120            // e.g. "- <Numeric Expression>"
121            return name + " " + getTypeDescription(argTypes[0]);
122        }
123    },
124
125    /**
126     * Defines syntax for expression invoked as <code>arg OPERATOR</code>
127     * (like <code>IS EMPTY</code>).
128     */
129    Postfix {
130        public void unparse(String fun, Exp[] args, PrintWriter pw) {
131            if (needParen(args)) {
132                ExpBase.unparseList(pw, args, "(", null, " " + fun + ")");
133            } else {
134                ExpBase.unparseList(pw, args, "", null, " " + fun);
135            }
136        }
137
138        public String getSignature(String name, int returnType, int[] argTypes)
139        {
140            // e.g. "<Expression> IS NULL"
141            return getTypeDescription(argTypes[0]) + " " + name;
142        }
143    },
144
145    /**
146     * Defines syntax for expression invoked as
147     * <code>{ARG, &#46;&#46;&#46;}</code>; that
148     * is, the set construction operator.
149     */
150    Braces {
151        public String getSignature(String name, int returnType, int[] argTypes)
152        {
153            return "{" + getTypeDescriptionCommaList(argTypes, 0) + "}";
154        }
155
156        public void unparse(String fun, Exp[] args, PrintWriter pw) {
157            ExpBase.unparseList(pw, args, "{", ", ", "}");
158        }
159    },
160
161    /**
162     * Defines syntax for expression invoked as <code>(ARG)</code> or
163     * <code>(ARG, &#46;&#46;&#46;)</code>; that is, parentheses for grouping
164     * expressions, and the tuple construction operator.
165     */
166    Parentheses {
167        public String getSignature(String name, int returnType, int[] argTypes)
168        {
169            return "(" + getTypeDescriptionCommaList(argTypes, 0) + ")";
170        }
171
172        public void unparse(String fun, Exp[] args, PrintWriter pw) {
173            ExpBase.unparseList(pw, args, "(", ", ", ")");
174        }
175    },
176
177    /**
178     * Defines syntax for expression invoked as <code>CASE ... END</code>.
179     */
180    Case {
181        public void unparse(String fun, Exp[] args, PrintWriter pw) {
182            if (fun.equals("_CaseTest")) {
183                pw.print("CASE");
184                int j = 0;
185                int clauseCount = (args.length - j) / 2;
186                for (int i = 0; i < clauseCount; i++) {
187                    pw.print(" WHEN ");
188                    args[j++].unparse(pw);
189                    pw.print(" THEN ");
190                    args[j++].unparse(pw);
191                }
192                if (j < args.length) {
193                    pw.print(" ELSE ");
194                    args[j++].unparse(pw);
195                }
196                Util.assertTrue(j == args.length);
197                pw.print(" END");
198            } else {
199                Util.assertTrue(fun.equals("_CaseMatch"));
200
201                pw.print("CASE ");
202                int j = 0;
203                args[j++].unparse(pw);
204                int clauseCount = (args.length - j) / 2;
205                for (int i = 0; i < clauseCount; i++) {
206                    pw.print(" WHEN ");
207                    args[j++].unparse(pw);
208                    pw.print(" THEN ");
209                    args[j++].unparse(pw);
210                }
211                if (j < args.length) {
212                    pw.print(" ELSE ");
213                    args[j++].unparse(pw);
214                }
215                Util.assertTrue(j == args.length);
216                pw.print(" END");
217            }
218        }
219
220        public String getSignature(String name, int returnType, int[] argTypes)
221        {
222            String s = getTypeDescription(argTypes[0]);
223            if (argTypes[0] == Category.Logical) {
224                return "CASE WHEN " + s + " THEN <Expression> ... END";
225            } else {
226                return "CASE " + s + " WHEN " + s
227                    + " THEN <Expression> ... END";
228            }
229        }
230    },
231
232    /**
233     * Defines syntax for expression generated by the Mondrian system which
234     * cannot be specified syntactically.
235     */
236    Internal,
237
238    /**
239     * Defines syntax for a CAST expression
240     * <code>CAST(expression AS type)</code>.
241     */
242    Cast {
243        public void unparse(String fun, Exp[] args, PrintWriter pw) {
244            pw.print("CAST(");
245            args[0].unparse(pw);
246            pw.print(" AS ");
247            args[1].unparse(pw);
248            pw.print(")");
249        }
250
251        public String getSignature(String name, int returnType, int[] argTypes)
252        {
253            return "CAST(<Expression> AS <Type>)";
254        }
255    },
256
257    /**
258     * Defines syntax for expression invoked <code>object&#46;&PROPERTY</code>
259     * (a variant of {@link #Property}).
260     */
261    QuotedProperty,
262
263    /**
264     * Defines syntax for expression invoked <code>object&#46;[&PROPERTY]</code>
265     * (a variant of {@link #Property}).
266     */
267    AmpersandQuotedProperty,
268
269    /**
270     * Defines the syntax for an empty expression. Empty expressions can occur
271     * within function calls, and are denoted by a pair of commas with only
272     * whitespace between them, for example
273     *
274     * <blockquote>
275     * <code>DrillDownLevelTop({[Product].[All Products]}, 3, ,
276     *  [Measures].[Unit Sales])</code>
277     * </blockquote>
278     */
279    Empty {
280        public void unparse(String fun, Exp[] args, PrintWriter pw) {
281            assert args.length == 0;
282        }
283        public String getSignature(String name, int returnType, int[] argTypes)
284        {
285            return "";
286        }};
287
288    /**
289     * Converts a call to a function of this syntax into source code.
290     *
291     * @param fun Function name
292     * @param args Arguments to the function
293     * @param pw Writer
294     */
295    public void unparse(String fun, Exp[] args, PrintWriter pw) {
296        throw new UnsupportedOperationException();
297    }
298
299    /**
300     * Returns a description of the signature of a function call, for
301     * example, "CoalesceEmpty(<Numeric Expression>, <String Expression>)".
302     *
303     * @param name Function name
304     * @param returnType Function's return category
305     * @param argTypes Categories of the function's arguments
306     * @return Function signature
307     */
308    public String getSignature(String name, int returnType, int[] argTypes) {
309        // e.g. "StripCalculatedMembers(<Set>)"
310        return (returnType == Category.Unknown
311                ? ""
312                : getTypeDescription(returnType) + " ")
313            + name + "(" + getTypeDescriptionCommaList(argTypes, 0)
314            + ")";
315    }
316
317    private static boolean needParen(Exp[] args) {
318        return !(args.length == 1
319                 && args[0] instanceof FunCall
320                 && ((FunCall) args[0]).getSyntax() == Syntax.Parentheses);
321    }
322
323    private static String getTypeDescription(int type) {
324        return "<" + Category.instance.getDescription(type & Category.Mask)
325            + ">";
326    }
327
328    private static String getTypeDescriptionCommaList(int[] types, int start) {
329        int initialSize = (types.length - start) * 16;
330        StringBuilder sb =
331            new StringBuilder(initialSize > 0 ? initialSize : 16);
332        for (int i = start; i < types.length; i++) {
333            if (i > start) {
334                sb.append(", ");
335            }
336            sb.append("<")
337                .append(
338                    Category.instance.getDescription(types[i] & Category.Mask))
339                .append(">");
340        }
341        return sb.toString();
342    }
343}
344
345// End Syntax.java