001    /*
002    // $Id: Syntax.java 247 2009-06-20 05:52:40Z 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-2008 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 247 2009-06-20 05:52:40Z 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                unparseList(
196                    writer,
197                    argList,
198                    "(",
199                    ", ",
200                    ")");
201            }
202        },
203    
204        /**
205         * Defines syntax for expression invoked as <code>CASE ... END</code>.
206         */
207        Case {
208            public void unparse(
209                String operatorName,
210                List<ParseTreeNode> argList,
211                ParseTreeWriter writer)
212            {
213                final PrintWriter pw = writer.getPrintWriter();
214                if (operatorName.equals("_CaseTest")) {
215                    pw.print("CASE");
216                    int j = 0;
217                    int clauseCount = (argList.size() - j) / 2;
218                    for (int i = 0; i < clauseCount; i++) {
219                        pw.print(" WHEN ");
220                        argList.get(j++).unparse(writer);
221                        pw.print(" THEN ");
222                        argList.get(j++).unparse(writer);
223                    }
224                    if (j < argList.size()) {
225                        pw.print(" ELSE ");
226                        argList.get(j++).unparse(writer);
227                    }
228                    assert j == argList.size();
229                    pw.print(" END");
230                } else {
231                    assert operatorName.equals("_CaseMatch");
232    
233                    pw.print("CASE ");
234                    int j = 0;
235                    argList.get(j++).unparse(writer);
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                }
250            }
251        },
252    
253        /**
254         * Defines syntax for expression generated by the system which
255         * cannot be specified syntactically.
256         */
257        Internal,
258    
259        /**
260         * Defines syntax for a CAST expression
261         * <code>CAST(expression AS type)</code>.
262         */
263        Cast {
264            public void unparse(
265                String operatorName,
266                List<ParseTreeNode> argList,
267                ParseTreeWriter writer)
268            {
269                writer.getPrintWriter().print("CAST(");
270                argList.get(0).unparse(writer);
271                writer.getPrintWriter().print(" AS ");
272                argList.get(1).unparse(writer);
273                writer.getPrintWriter().print(")");
274            }
275        },
276    
277        /**
278         * Defines syntax for expression invoked <code>object&#46;&PROPERTY</code>
279         * (a variant of {@link #Property}).
280         */
281        QuotedProperty,
282    
283        /**
284         * Defines syntax for expression invoked <code>object&#46;[&PROPERTY]</code>
285         * (a variant of {@link #Property}).
286         */
287        AmpersandQuotedProperty;
288    
289        /**
290         * Converts a call to a function of this syntax into source code.
291         *
292         * @param operatorName Operator name
293         * @param argList List of arguments
294         * @param writer Writer
295         */
296        public void unparse(
297            String operatorName,
298            List<ParseTreeNode> argList,
299            ParseTreeWriter writer)
300        {
301            throw new UnsupportedOperationException();
302        }
303    
304        /**
305         * Returns whether a collection of parse tree nodes need to be enclosed
306         * in parentheses.
307         *
308         * @param args Parse tree nodes
309         * @return Whether nodes need to be enclosed in parentheses
310         */
311        private static boolean needParen(List<ParseTreeNode> args) {
312            return !(args.size() == 1
313                     && args.get(0) instanceof CallNode
314                     && ((CallNode) args.get(0)).getSyntax() == Parentheses);
315        }
316    
317        private static void unparseList(
318            ParseTreeWriter writer,
319            List<ParseTreeNode> argList,
320            String start,
321            String mid,
322            String end)
323        {
324            final PrintWriter pw = writer.getPrintWriter();
325            pw.print(start);
326            for (int i = 0; i < argList.size(); i++) {
327                if (i > 0) {
328                    pw.print(mid);
329                }
330                argList.get(i).unparse(writer);
331            }
332            pw.print(end);
333        }
334    }
335    
336    // End Syntax.java