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