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) 2005-2005 Julian Hyde 008// Copyright (C) 2005-2011 Pentaho and others 009// All Rights Reserved. 010*/ 011package mondrian.olap.fun; 012 013import mondrian.olap.*; 014 015import java.lang.reflect.Array; 016import java.util.ArrayList; 017import java.util.List; 018 019/** 020 * Support class for the {@link mondrian.tui.CmdRunner} allowing one to view 021 * available functions and their syntax. 022 * 023 * @author Richard M. Emberson 024 */ 025public class FunInfo implements Comparable<FunInfo> { 026 private final Syntax syntax; 027 private final String name; 028 private final String description; 029 private final int[] returnTypes; 030 private final int[][] parameterTypes; 031 private String[] sigs; 032 033 static FunInfo make(Resolver resolver) { 034 FunDef funDef = resolver.getFunDef(); 035 if (funDef != null) { 036 return new FunInfo(funDef); 037 } else if (resolver instanceof MultiResolver) { 038 return new FunInfo((MultiResolver) resolver); 039 } else { 040 return new FunInfo(resolver); 041 } 042 } 043 044 FunInfo(FunDef funDef) { 045 this.syntax = funDef.getSyntax(); 046 this.name = funDef.getName(); 047 assert name != null; 048 assert syntax != null; 049 this.returnTypes = new int[] { funDef.getReturnCategory() }; 050 this.parameterTypes = new int[][] { funDef.getParameterCategories() }; 051 052 // use explicit signature if it has one, otherwise generate a set 053 this.sigs = funDef instanceof FunDefBase 054 && ((FunDefBase) funDef).signature != null 055 ? new String[] {((FunDefBase) funDef).signature} 056 : makeSigs(syntax, name, returnTypes, parameterTypes); 057 this.description = funDef.getDescription(); 058 } 059 060 FunInfo(MultiResolver multiResolver) { 061 this.syntax = multiResolver.getSyntax(); 062 this.name = multiResolver.getName(); 063 assert name != null; 064 assert syntax != null; 065 this.description = multiResolver.getDescription(); 066 067 String[] signatures = multiResolver.getSignatures(); 068 this.returnTypes = new int[signatures.length]; 069 this.parameterTypes = new int[signatures.length][]; 070 for (int i = 0; i < signatures.length; i++) { 071 returnTypes[i] = FunUtil.decodeReturnCategory(signatures[i]); 072 parameterTypes[i] = 073 FunUtil.decodeParameterCategories(signatures[i]); 074 } 075 this.sigs = makeSigs(syntax, name, returnTypes, parameterTypes); 076 } 077 078 FunInfo(Resolver resolver) { 079 this.syntax = resolver.getSyntax(); 080 this.name = resolver.getName(); 081 assert name != null; 082 assert syntax != null; 083 this.description = resolver.getDescription(); 084 this.returnTypes = null; 085 this.parameterTypes = null; 086 final String signature = resolver.getSignature(); 087 this.sigs = 088 signature == null 089 ? new String[0] 090 : new String[] {signature}; 091 } 092 093 FunInfo( 094 String name, 095 String description, 096 String flags) 097 { 098 this.name = name; 099 this.description = description; 100 this.syntax = FunUtil.decodeSyntacticType(flags); 101 this.returnTypes = new int[] {FunUtil.decodeReturnCategory(flags)}; 102 this.parameterTypes = 103 new int[][] {FunUtil.decodeParameterCategories(flags)}; 104 } 105 106 public String[] getSignatures() { 107 return sigs; 108 } 109 110 private static String[] makeSigs( 111 Syntax syntax, 112 String name, 113 int[] returnTypes, 114 int[][] parameterTypes) 115 { 116 if (parameterTypes == null) { 117 return null; 118 } 119 120 String[] sigs = new String[parameterTypes.length]; 121 for (int i = 0; i < sigs.length; i++) { 122 sigs[i] = syntax.getSignature( 123 name, returnTypes[i], parameterTypes[i]); 124 } 125 return sigs; 126 } 127 128 /** 129 * Returns the syntactic type of the function. 130 */ 131 public Syntax getSyntax() { 132 return this.syntax; 133 } 134 135 /** 136 * Returns the name of this function. 137 */ 138 public String getName() { 139 return this.name; 140 } 141 142 /** 143 * Returns the description of this function. 144 */ 145 public String getDescription() { 146 return this.description; 147 } 148 149 /** 150 * Returns the type of value returned by this function. Values are the same 151 * as those returned by {@link mondrian.olap.Exp#getCategory()}. 152 */ 153 public int[] getReturnCategories() { 154 return this.returnTypes; 155 } 156 157 /** 158 * Returns the types of the arguments of this function. Values are the same 159 * as those returned by {@link mondrian.olap.Exp#getCategory()}. The 160 * 0<sup>th</sup> argument of methods and properties are the object they 161 * are applied to. Infix operators have two arguments, and prefix operators 162 * have one argument. 163 */ 164 public int[][] getParameterCategories() { 165 return this.parameterTypes; 166 } 167 168 public int compareTo(FunInfo fi) { 169 int c = this.name.compareTo(fi.name); 170 if (c != 0) { 171 return c; 172 } 173 final List<Object> pcList = toList(this.getParameterCategories()); 174 final String pc = pcList.toString(); 175 final List otherPcList = toList(fi.getParameterCategories()); 176 final String otherPc = otherPcList.toString(); 177 return pc.compareTo(otherPc); 178 } 179 180 public boolean equals(Object obj) { 181 if (obj instanceof FunInfo) { 182 final FunInfo that = (FunInfo) obj; 183 if (!name.equals(that.name)) { 184 return false; 185 } 186 final List<Object> pcList = toList(this.getParameterCategories()); 187 final List<Object> pcList2 = toList(that.getParameterCategories()); 188 return pcList.equals(pcList2); 189 } else { 190 return false; 191 } 192 } 193 194 public int hashCode() { 195 int h = name.hashCode(); 196 final List<Object> pcList = toList(this.getParameterCategories()); 197 return Util.hash(h, pcList); 198 } 199 200 private static List<Object> toList(Object a) { 201 final List<Object> list = new ArrayList<Object>(); 202 if (a == null) { 203 return list; 204 } 205 final int length = Array.getLength(a); 206 for (int i = 0; i < length; i++) { 207 final Object o = Array.get(a, i); 208 if (o.getClass().isArray()) { 209 list.add(toList(o)); 210 } else { 211 list.add(o); 212 } 213 } 214 return list; 215 } 216} 217 218// End FunInfo.java