001/* 002// This software is subject to the terms of the Eclipse Public License v1.0 003// Agreement, available at the following URL: 004// http://www.eclipse.org/legal/epl-v10.html. 005// You must accept the terms of that agreement to use this software. 006// 007// Copyright (C) 2003-2005 Julian Hyde 008// Copyright (C) 2005-2009 Pentaho 009// All Rights Reserved. 010*/ 011package mondrian.olap; 012 013import java.io.PrintWriter; 014 015/** 016 * Enumerated values describing the syntax of an expression. 017 * 018 * @author jhyde 019 * @since 21 July, 2003 020 */ 021public enum Syntax { 022 /** 023 * Defines syntax for expression invoked <code>FUNCTION()</code> or 024 * <code>FUNCTION(args)</code>. 025 */ 026 Function { 027 public void unparse(String fun, Exp[] args, PrintWriter pw) { 028 ExpBase.unparseList(pw, args, fun + "(", ", ", ")"); 029 } 030 }, 031 032 /** 033 * Defines syntax for expression invoked as <code>object.PROPERTY</code>. 034 */ 035 Property { 036 public void unparse(String fun, Exp[] args, PrintWriter pw) { 037 Util.assertTrue(args.length >= 1); 038 args[0].unparse(pw); // 'this' 039 pw.print("."); 040 pw.print(fun); 041 } 042 043 public String getSignature( 044 String name, int returnType, int[] argTypes) 045 { 046 // e.g. "<Set>.Current" 047 return getTypeDescription(argTypes[0]) + "." + name; 048 } 049 }, 050 051 /** 052 * Defines syntax for expression invoked invoked as 053 * <code>object.METHOD()</code> or 054 * <code>object.METHOD(args)</code>. 055 */ 056 Method { 057 public void unparse(String fun, Exp[] args, PrintWriter pw) { 058 Util.assertTrue(args.length >= 1); 059 args[0].unparse(pw); // 'this' 060 pw.print("."); 061 pw.print(fun); 062 pw.print("("); 063 for (int i = 1; i < args.length; i++) { 064 if (i > 1) { 065 pw.print(", "); 066 } 067 args[i].unparse(pw); 068 } 069 pw.print(")"); 070 } 071 072 public String getSignature(String name, int returnType, int[] argTypes) 073 { 074 // e.g. "<Member>.Lead(<Numeric Expression>)" 075 return (returnType == Category.Unknown 076 ? "" 077 : getTypeDescription(returnType) + " ") 078 + getTypeDescription(argTypes[0]) + "." 079 + name + "(" + getTypeDescriptionCommaList(argTypes, 1) 080 + ")"; 081 } 082 }, 083 084 /** 085 * Defines syntax for expression invoked as <code>arg OPERATOR arg</code> 086 * (like '+' or 'AND'). 087 */ 088 Infix { 089 public void unparse(String fun, Exp[] args, PrintWriter pw) { 090 if (needParen(args)) { 091 ExpBase.unparseList(pw, args, "(", " " + fun + " ", ")"); 092 } else { 093 ExpBase.unparseList(pw, args, "", " " + fun + " ", ""); 094 } 095 } 096 097 public String getSignature(String name, int returnType, int[] argTypes) 098 { 099 // e.g. "<Numeric Expression> / <Numeric Expression>" 100 return getTypeDescription(argTypes[0]) + " " + name + " " 101 + getTypeDescription(argTypes[1]); 102 } 103 }, 104 105 /** 106 * Defines syntax for expression invoked as <code>OPERATOR arg</code> 107 * (like unary '-'). 108 */ 109 Prefix { 110 public void unparse(String fun, Exp[] args, PrintWriter pw) { 111 if (needParen(args)) { 112 ExpBase.unparseList(pw, args, "(" + fun + " ", null, ")"); 113 } else { 114 ExpBase.unparseList(pw, args, fun + " ", null, ""); 115 } 116 } 117 118 public String getSignature(String name, int returnType, int[] argTypes) 119 { 120 // e.g. "- <Numeric Expression>" 121 return name + " " + getTypeDescription(argTypes[0]); 122 } 123 }, 124 125 /** 126 * Defines syntax for expression invoked as <code>arg OPERATOR</code> 127 * (like <code>IS EMPTY</code>). 128 */ 129 Postfix { 130 public void unparse(String fun, Exp[] args, PrintWriter pw) { 131 if (needParen(args)) { 132 ExpBase.unparseList(pw, args, "(", null, " " + fun + ")"); 133 } else { 134 ExpBase.unparseList(pw, args, "", null, " " + fun); 135 } 136 } 137 138 public String getSignature(String name, int returnType, int[] argTypes) 139 { 140 // e.g. "<Expression> IS NULL" 141 return getTypeDescription(argTypes[0]) + " " + name; 142 } 143 }, 144 145 /** 146 * Defines syntax for expression invoked as 147 * <code>{ARG, ...}</code>; that 148 * is, the set construction operator. 149 */ 150 Braces { 151 public String getSignature(String name, int returnType, int[] argTypes) 152 { 153 return "{" + getTypeDescriptionCommaList(argTypes, 0) + "}"; 154 } 155 156 public void unparse(String fun, Exp[] args, PrintWriter pw) { 157 ExpBase.unparseList(pw, args, "{", ", ", "}"); 158 } 159 }, 160 161 /** 162 * Defines syntax for expression invoked as <code>(ARG)</code> or 163 * <code>(ARG, ...)</code>; that is, parentheses for grouping 164 * expressions, and the tuple construction operator. 165 */ 166 Parentheses { 167 public String getSignature(String name, int returnType, int[] argTypes) 168 { 169 return "(" + getTypeDescriptionCommaList(argTypes, 0) + ")"; 170 } 171 172 public void unparse(String fun, Exp[] args, PrintWriter pw) { 173 ExpBase.unparseList(pw, args, "(", ", ", ")"); 174 } 175 }, 176 177 /** 178 * Defines syntax for expression invoked as <code>CASE ... END</code>. 179 */ 180 Case { 181 public void unparse(String fun, Exp[] args, PrintWriter pw) { 182 if (fun.equals("_CaseTest")) { 183 pw.print("CASE"); 184 int j = 0; 185 int clauseCount = (args.length - j) / 2; 186 for (int i = 0; i < clauseCount; i++) { 187 pw.print(" WHEN "); 188 args[j++].unparse(pw); 189 pw.print(" THEN "); 190 args[j++].unparse(pw); 191 } 192 if (j < args.length) { 193 pw.print(" ELSE "); 194 args[j++].unparse(pw); 195 } 196 Util.assertTrue(j == args.length); 197 pw.print(" END"); 198 } else { 199 Util.assertTrue(fun.equals("_CaseMatch")); 200 201 pw.print("CASE "); 202 int j = 0; 203 args[j++].unparse(pw); 204 int clauseCount = (args.length - j) / 2; 205 for (int i = 0; i < clauseCount; i++) { 206 pw.print(" WHEN "); 207 args[j++].unparse(pw); 208 pw.print(" THEN "); 209 args[j++].unparse(pw); 210 } 211 if (j < args.length) { 212 pw.print(" ELSE "); 213 args[j++].unparse(pw); 214 } 215 Util.assertTrue(j == args.length); 216 pw.print(" END"); 217 } 218 } 219 220 public String getSignature(String name, int returnType, int[] argTypes) 221 { 222 String s = getTypeDescription(argTypes[0]); 223 if (argTypes[0] == Category.Logical) { 224 return "CASE WHEN " + s + " THEN <Expression> ... END"; 225 } else { 226 return "CASE " + s + " WHEN " + s 227 + " THEN <Expression> ... END"; 228 } 229 } 230 }, 231 232 /** 233 * Defines syntax for expression generated by the Mondrian system which 234 * cannot be specified syntactically. 235 */ 236 Internal, 237 238 /** 239 * Defines syntax for a CAST expression 240 * <code>CAST(expression AS type)</code>. 241 */ 242 Cast { 243 public void unparse(String fun, Exp[] args, PrintWriter pw) { 244 pw.print("CAST("); 245 args[0].unparse(pw); 246 pw.print(" AS "); 247 args[1].unparse(pw); 248 pw.print(")"); 249 } 250 251 public String getSignature(String name, int returnType, int[] argTypes) 252 { 253 return "CAST(<Expression> AS <Type>)"; 254 } 255 }, 256 257 /** 258 * Defines syntax for expression invoked <code>object.&PROPERTY</code> 259 * (a variant of {@link #Property}). 260 */ 261 QuotedProperty, 262 263 /** 264 * Defines syntax for expression invoked <code>object.[&PROPERTY]</code> 265 * (a variant of {@link #Property}). 266 */ 267 AmpersandQuotedProperty, 268 269 /** 270 * Defines the syntax for an empty expression. Empty expressions can occur 271 * within function calls, and are denoted by a pair of commas with only 272 * whitespace between them, for example 273 * 274 * <blockquote> 275 * <code>DrillDownLevelTop({[Product].[All Products]}, 3, , 276 * [Measures].[Unit Sales])</code> 277 * </blockquote> 278 */ 279 Empty { 280 public void unparse(String fun, Exp[] args, PrintWriter pw) { 281 assert args.length == 0; 282 } 283 public String getSignature(String name, int returnType, int[] argTypes) 284 { 285 return ""; 286 }}; 287 288 /** 289 * Converts a call to a function of this syntax into source code. 290 * 291 * @param fun Function name 292 * @param args Arguments to the function 293 * @param pw Writer 294 */ 295 public void unparse(String fun, Exp[] args, PrintWriter pw) { 296 throw new UnsupportedOperationException(); 297 } 298 299 /** 300 * Returns a description of the signature of a function call, for 301 * example, "CoalesceEmpty(<Numeric Expression>, <String Expression>)". 302 * 303 * @param name Function name 304 * @param returnType Function's return category 305 * @param argTypes Categories of the function's arguments 306 * @return Function signature 307 */ 308 public String getSignature(String name, int returnType, int[] argTypes) { 309 // e.g. "StripCalculatedMembers(<Set>)" 310 return (returnType == Category.Unknown 311 ? "" 312 : getTypeDescription(returnType) + " ") 313 + name + "(" + getTypeDescriptionCommaList(argTypes, 0) 314 + ")"; 315 } 316 317 private static boolean needParen(Exp[] args) { 318 return !(args.length == 1 319 && args[0] instanceof FunCall 320 && ((FunCall) args[0]).getSyntax() == Syntax.Parentheses); 321 } 322 323 private static String getTypeDescription(int type) { 324 return "<" + Category.instance.getDescription(type & Category.Mask) 325 + ">"; 326 } 327 328 private static String getTypeDescriptionCommaList(int[] types, int start) { 329 int initialSize = (types.length - start) * 16; 330 StringBuilder sb = 331 new StringBuilder(initialSize > 0 ? initialSize : 16); 332 for (int i = start; i < types.length; i++) { 333 if (i > start) { 334 sb.append(", "); 335 } 336 sb.append("<") 337 .append( 338 Category.instance.getDescription(types[i] & Category.Mask)) 339 .append(">"); 340 } 341 return sb.toString(); 342 } 343} 344 345// End Syntax.java