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