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, ...}</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, ...)</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.&PROPERTY</code>
298 * (a variant of {@link #Property}).
299 */
300 QuotedProperty,
301
302 /**
303 * Defines syntax for expression invoked <code>object.[&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