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*/
020package org.olap4j.mdx;
021
022import java.io.PrintWriter;
023import 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 */
032public 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