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