1 /* 2 * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Sun designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Sun in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 22 * CA 95054 USA or visit www.sun.com if you need additional information or 23 * have any questions. 24 */ 25 26 package com.sun.tools.apt.mirror.declaration; 27 28 29 import java.util.Collection; 30 31 import com.sun.mirror.declaration.*; 32 import com.sun.mirror.type.TypeMirror; 33 import com.sun.tools.apt.mirror.type.TypeMirrorImpl; 34 import com.sun.tools.javac.code.Type; 35 36 import static com.sun.tools.javac.code.TypeTags.*; 37 38 39 /** 40 * Utility class for operating on constant expressions. 41 */ 42 @SuppressWarnings("deprecation") 43 class Constants { 44 45 /** 46 * Converts a constant in javac's internal representation (in which 47 * boolean, char, byte, short, and int are each represented by an Integer) 48 * into standard representation. Other values (including null) are 49 * returned unchanged. 50 */ 51 static Object decodeConstant(Object value, Type type) { 52 if (value instanceof Integer) { 53 int i = ((Integer) value).intValue(); 54 switch (type.tag) { 55 case BOOLEAN: return Boolean.valueOf(i != 0); 56 case CHAR: return Character.valueOf((char) i); 57 case BYTE: return Byte.valueOf((byte) i); 58 case SHORT: return Short.valueOf((short) i); 59 } 60 } 61 return value; 62 } 63 64 /** 65 * Returns a formatter for generating the text of constant 66 * expressions. Equivalent to 67 * <tt>getFormatter(new StringBuilder())</tt>. 68 */ 69 static Formatter getFormatter() { 70 return new Formatter(new StringBuilder()); 71 } 72 73 /** 74 * Returns a formatter for generating the text of constant 75 * expressions. Also generates the text of constant 76 * "pseudo-expressions" for annotations and array-valued 77 * annotation elements. 78 * 79 * @param buf where the expression is written 80 */ 81 static Formatter getFormatter(StringBuilder buf) { 82 return new Formatter(buf); 83 } 84 85 86 /** 87 * Utility class used to generate the text of constant 88 * expressions. Also generates the text of constant 89 * "pseudo-expressions" for annotations and array-valued 90 * annotation elements. 91 */ 92 static class Formatter { 93 94 private StringBuilder buf; // where the output goes 95 96 private Formatter(StringBuilder buf) { 97 this.buf = buf; 98 } 99 100 101 public String toString() { 102 return buf.toString(); 103 } 104 105 /** 106 * Appends a constant whose type is not statically known 107 * by dispatching to the appropriate overloaded append method. 108 */ 109 void append(Object val) { 110 if (val instanceof String) { 111 append((String) val); 112 } else if (val instanceof Character) { 113 append((Character) val); 114 } else if (val instanceof Boolean) { 115 append((Boolean) val); 116 } else if (val instanceof Byte) { 117 append((Byte) val); 118 } else if (val instanceof Short) { 119 append((Short) val); 120 } else if (val instanceof Integer) { 121 append((Integer) val); 122 } else if (val instanceof Long) { 123 append((Long) val); 124 } else if (val instanceof Float) { 125 append((Float) val); 126 } else if (val instanceof Double) { 127 append((Double) val); 128 } else if (val instanceof TypeMirror) { 129 append((TypeMirrorImpl) val); 130 } else if (val instanceof EnumConstantDeclaration) { 131 append((EnumConstantDeclarationImpl) val); 132 } else if (val instanceof AnnotationMirror) { 133 append((AnnotationMirrorImpl) val); 134 } else if (val instanceof Collection<?>) { 135 append((Collection<?>) val); 136 } else { 137 appendUnquoted(val.toString()); 138 } 139 } 140 141 /** 142 * Appends a string, escaped (as needed) and quoted. 143 */ 144 void append(String val) { 145 buf.append('"'); 146 appendUnquoted(val); 147 buf.append('"'); 148 } 149 150 /** 151 * Appends a Character, escaped (as needed) and quoted. 152 */ 153 void append(Character val) { 154 buf.append('\''); 155 appendUnquoted(val.charValue()); 156 buf.append('\''); 157 } 158 159 void append(Boolean val) { 160 buf.append(val); 161 } 162 163 void append(Byte val) { 164 buf.append(String.format("0x%02x", val)); 165 } 166 167 void append(Short val) { 168 buf.append(val); 169 } 170 171 void append(Integer val) { 172 buf.append(val); 173 } 174 175 void append(Long val) { 176 buf.append(val).append('L'); 177 } 178 179 void append(Float val) { 180 if (val.isNaN()) { 181 buf.append("0.0f/0.0f"); 182 } else if (val.isInfinite()) { 183 if (val.floatValue() < 0) { 184 buf.append('-'); 185 } 186 buf.append("1.0f/0.0f"); 187 } else { 188 buf.append(val).append('f'); 189 } 190 } 191 192 void append(Double val) { 193 if (val.isNaN()) { 194 buf.append("0.0/0.0"); 195 } else if (val.isInfinite()) { 196 if (val.doubleValue() < 0) { 197 buf.append('-'); 198 } 199 buf.append("1.0/0.0"); 200 } else { 201 buf.append(val); 202 } 203 } 204 205 /** 206 * Appends the class literal corresponding to a type. Should 207 * only be invoked for types that have an associated literal. 208 * e.g: "java.lang.String.class" 209 * "boolean.class" 210 * "int[].class" 211 */ 212 void append(TypeMirrorImpl t) { 213 appendUnquoted(t.type.toString()); 214 buf.append(".class"); 215 } 216 217 /** 218 * Appends the fully qualified name of an enum constant. 219 * e.g: "java.math.RoundingMode.UP" 220 */ 221 void append(EnumConstantDeclarationImpl e) { 222 appendUnquoted(e.sym.enclClass() + "." + e); 223 } 224 225 /** 226 * Appends the text of an annotation pseudo-expression. 227 * e.g: "@pkg.Format(linesep='\n')" 228 */ 229 void append(AnnotationMirrorImpl anno) { 230 appendUnquoted(anno.toString()); 231 } 232 233 /** 234 * Appends the elements of a collection, enclosed within braces 235 * and separated by ", ". Useful for array-valued annotation 236 * elements. 237 */ 238 void append(Collection<?> vals) { 239 buf.append('{'); 240 boolean first = true; 241 for (Object val : vals) { 242 if (first) { 243 first = false; 244 } else { 245 buf.append(", "); 246 } 247 append(((AnnotationValue) val).getValue()); 248 } 249 buf.append('}'); 250 } 251 252 253 /** 254 * For each char of a string, append using appendUnquoted(char). 255 */ 256 private void appendUnquoted(String s) { 257 for (char c : s.toCharArray()) { 258 appendUnquoted(c); 259 } 260 } 261 262 /** 263 * Appends a char (unquoted), using escapes for those that are not 264 * printable ASCII. We don't know what is actually printable in 265 * the locale in which this result will be used, so ASCII is our 266 * best guess as to the least common denominator. 267 */ 268 private void appendUnquoted(char c) { 269 switch (c) { 270 case '\b': buf.append("\\b"); break; 271 case '\t': buf.append("\\t"); break; 272 case '\n': buf.append("\\n"); break; 273 case '\f': buf.append("\\f"); break; 274 case '\r': buf.append("\\r"); break; 275 case '\"': buf.append("\\\""); break; 276 case '\'': buf.append("\\\'"); break; 277 case '\\': buf.append("\\\\"); break; 278 default: 279 if (isPrintableAscii(c)) { 280 buf.append(c); 281 } else { 282 buf.append(String.format("\\u%04x", (int) c)); 283 } 284 } 285 } 286 287 /** 288 * Is c a printable ASCII character? 289 */ 290 private static boolean isPrintableAscii(char c) { 291 return c >= ' ' && c <= '~'; 292 } 293 } 294 }