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