001    /*
002    // $Id: Syntax.java 359 2010-10-14 21:24:51Z jhyde $
003    // This software is subject to the terms of the Eclipse Public License v1.0
004    // Agreement, available at the following URL:
005    // http://www.eclipse.org/legal/epl-v10.html.
006    // Copyright (C) 2007-2010 Julian Hyde
007    // All Rights Reserved.
008    // You must accept the terms of that agreement to use this software.
009    */
010    package org.olap4j.mdx;
011    
012    import java.io.PrintWriter;
013    import java.util.List;
014    
015    /**
016     * Enumerated values describing the syntax of an expression.
017     *
018     * @author jhyde
019     * @since 21 July, 2003
020     * @version $Id: Syntax.java 359 2010-10-14 21:24:51Z jhyde $
021     */
022    public enum Syntax {
023        /**
024         * Defines syntax for expression invoked <code>FUNCTION()</code> or
025         * <code>FUNCTION(args)</code>.
026         */
027        Function {
028            public void unparse(
029                String operatorName,
030                List<ParseTreeNode> argList,
031                ParseTreeWriter writer)
032            {
033                unparseList(writer, argList, operatorName + "(", ", ", ")");
034            }
035        },
036    
037        /**
038         * Defines syntax for expression invoked as <code>object.PROPERTY</code>.
039         */
040        Property {
041            public void unparse(
042                String operatorName,
043                List<ParseTreeNode> argList,
044                ParseTreeWriter writer)
045            {
046                assert argList.size() == 1;
047                argList.get(0).unparse(writer); // 'this'
048                writer.getPrintWriter().print(".");
049                writer.getPrintWriter().print(operatorName);
050            }
051        },
052    
053        /**
054         * Defines syntax for expression invoked invoked as
055         * <code>object.METHOD()</code> or
056         * <code>object.METHOD(args)</code>.
057         */
058        Method {
059            public void unparse(
060                String operatorName,
061                List<ParseTreeNode> argList,
062                ParseTreeWriter writer)
063            {
064                assert argList.size() >= 1;
065                argList.get(0).unparse(writer); // 'this'
066                final PrintWriter pw = writer.getPrintWriter();
067                pw.print(".");
068                pw.print(operatorName);
069                pw.print("(");
070                for (int i = 1; i < argList.size(); i++) {
071                    if (i > 1) {
072                        pw.print(", ");
073                    }
074                    argList.get(i).unparse(writer);
075                }
076                pw.print(")");
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(
086                String operatorName,
087                List<ParseTreeNode> argList,
088                ParseTreeWriter writer)
089            {
090                if (needParen(argList)) {
091                    unparseList(
092                        writer,
093                        argList,
094                        "(",
095                        " " + operatorName + " ",
096                        ")");
097                } else {
098                    unparseList(
099                        writer,
100                        argList,
101                        "",
102                        " " + operatorName + " ",
103                        "");
104                }
105            }
106        },
107    
108        /**
109         * Defines syntax for expression invoked as <code>OPERATOR arg</code>
110         * (like unary '-').
111         */
112        Prefix {
113            public void unparse(
114                String operatorName,
115                List<ParseTreeNode> argList,
116                ParseTreeWriter writer)
117            {
118                if (needParen(argList)) {
119                    unparseList(
120                        writer,
121                        argList,
122                        "(" + operatorName + " ",
123                        null,
124                        ")");
125                } else {
126                    unparseList(
127                        writer,
128                        argList,
129                        operatorName + " ",
130                        null,
131                        "");
132                }
133            }
134        },
135    
136        /**
137         * Defines syntax for expression invoked as <code>arg OPERATOR</code>
138         * (like <code>IS EMPTY</code>).
139         */
140        Postfix {
141            public void unparse(
142                String operatorName,
143                List<ParseTreeNode> argList,
144                ParseTreeWriter writer)
145            {
146                if (needParen(argList)) {
147                    unparseList(
148                        writer,
149                        argList,
150                        "(",
151                        null,
152                        " " + operatorName + ")");
153                } else {
154                    unparseList(
155                        writer,
156                        argList,
157                        "",
158                        null,
159                        " " + operatorName);
160                }
161            }
162        },
163    
164        /**
165         * Defines syntax for expression invoked as
166         * <code>{ARG, &#46;&#46;&#46;}</code>; that
167         * is, the set construction operator.
168         */
169        Braces {
170            public void unparse(
171                String operatorName,
172                List<ParseTreeNode> argList,
173                ParseTreeWriter writer)
174            {
175                unparseList(
176                    writer,
177                    argList,
178                    "{",
179                    ", ",
180                    "}");
181            }
182        },
183    
184        /**
185         * Defines syntax for expression invoked as <code>(ARG)</code> or
186         * <code>(ARG, &#46;&#46;&#46;)</code>; that is, parentheses for grouping
187         * expressions, and the tuple construction operator.
188         */
189        Parentheses {
190            public void unparse(
191                String operatorName,
192                List<ParseTreeNode> argList,
193                ParseTreeWriter writer)
194            {
195                if (argList.size() == 1
196                    && argList.get(0) instanceof CallNode
197                    && needParen(((CallNode) argList.get(0)).getArgList()))
198                {
199                    // The parenthesized expression is going to defensively
200                    // parenthesize itself. So, don't add another layer.
201                    argList.get(0).unparse(writer);
202                } else {
203                    unparseList(
204                        writer,
205                        argList,
206                        "(",
207                        ", ",
208                        ")");
209                }
210            }
211        },
212    
213        /**
214         * Defines syntax for expression invoked as <code>CASE ... END</code>.
215         */
216        Case {
217            public void unparse(
218                String operatorName,
219                List<ParseTreeNode> argList,
220                ParseTreeWriter writer)
221            {
222                final PrintWriter pw = writer.getPrintWriter();
223                if (operatorName.equals("_CaseTest")) {
224                    pw.print("CASE");
225                    int j = 0;
226                    int clauseCount = (argList.size() - j) / 2;
227                    for (int i = 0; i < clauseCount; i++) {
228                        pw.print(" WHEN ");
229                        argList.get(j++).unparse(writer);
230                        pw.print(" THEN ");
231                        argList.get(j++).unparse(writer);
232                    }
233                    if (j < argList.size()) {
234                        pw.print(" ELSE ");
235                        argList.get(j++).unparse(writer);
236                    }
237                    assert j == argList.size();
238                    pw.print(" END");
239                } else {
240                    assert operatorName.equals("_CaseMatch");
241    
242                    pw.print("CASE ");
243                    int j = 0;
244                    argList.get(j++).unparse(writer);
245                    int clauseCount = (argList.size() - j) / 2;
246                    for (int i = 0; i < clauseCount; i++) {
247                        pw.print(" WHEN ");
248                        argList.get(j++).unparse(writer);
249                        pw.print(" THEN ");
250                        argList.get(j++).unparse(writer);
251                    }
252                    if (j < argList.size()) {
253                        pw.print(" ELSE ");
254                        argList.get(j++).unparse(writer);
255                    }
256                    assert j == argList.size();
257                    pw.print(" END");
258                }
259            }
260        },
261    
262        /**
263         * Defines syntax for expression generated by the system which
264         * cannot be specified syntactically.
265         */
266        Internal,
267    
268        /**
269         * Defines syntax for a CAST expression
270         * <code>CAST(expression AS type)</code>.
271         */
272        Cast {
273            public void unparse(
274                String operatorName,
275                List<ParseTreeNode> argList,
276                ParseTreeWriter writer)
277            {
278                writer.getPrintWriter().print("CAST(");
279                argList.get(0).unparse(writer);
280                writer.getPrintWriter().print(" AS ");
281                argList.get(1).unparse(writer);
282                writer.getPrintWriter().print(")");
283            }
284        },
285    
286        /**
287         * Defines syntax for expression invoked <code>object&#46;&PROPERTY</code>
288         * (a variant of {@link #Property}).
289         */
290        QuotedProperty,
291    
292        /**
293         * Defines syntax for expression invoked <code>object&#46;[&PROPERTY]</code>
294         * (a variant of {@link #Property}).
295         */
296        AmpersandQuotedProperty,
297    
298        /**
299         * Defines the syntax for an empty expression. Empty expressions can occur
300         * within function calls, and are denoted by a pair of commas with only
301         * whitespace between them, for example
302         *
303         * <blockquote>
304         * <code>DrillDownLevelTop({[Product].[All Products]}, 3, ,
305         *  [Measures].[Unit Sales])</code>
306         * </blockquote>
307         */
308        Empty {
309            public void unparse(
310                String operatorName,
311                List<ParseTreeNode> argList,
312                ParseTreeWriter writer)
313            {
314                assert argList.size() == 0;
315            }
316        };
317    
318        /**
319         * Converts a call to a function of this syntax into source code.
320         *
321         * @param operatorName Operator name
322         * @param argList List of arguments
323         * @param writer Writer
324         */
325        public void unparse(
326            String operatorName,
327            List<ParseTreeNode> argList,
328            ParseTreeWriter writer)
329        {
330            throw new UnsupportedOperationException();
331        }
332    
333        /**
334         * Returns whether a collection of parse tree nodes need to be enclosed
335         * in parentheses.
336         *
337         * @param args Parse tree nodes
338         * @return Whether nodes need to be enclosed in parentheses
339         */
340        private static boolean needParen(List<ParseTreeNode> args) {
341            return !(args.size() == 1
342                     && args.get(0) instanceof CallNode
343                     && ((CallNode) args.get(0)).getSyntax() == Parentheses);
344        }
345    
346        private static void unparseList(
347            ParseTreeWriter writer,
348            List<ParseTreeNode> argList,
349            String start,
350            String mid,
351            String end)
352        {
353            final PrintWriter pw = writer.getPrintWriter();
354            pw.print(start);
355            for (int i = 0; i < argList.size(); i++) {
356                if (i > 0) {
357                    pw.print(mid);
358                }
359                argList.get(i).unparse(writer);
360            }
361            pw.print(end);
362        }
363    }
364    
365    // End Syntax.java