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, ...}</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, ...)</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.&PROPERTY</code>
288 * (a variant of {@link #Property}).
289 */
290 QuotedProperty,
291
292 /**
293 * Defines syntax for expression invoked <code>object.[&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