001 /*
002 * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package com.sun.tools.apt.mirror.declaration;
027
028
029 import java.util.Collection;
030
031 import com.sun.mirror.declaration.*;
032 import com.sun.mirror.type.TypeMirror;
033 import com.sun.tools.apt.mirror.type.TypeMirrorImpl;
034 import com.sun.tools.javac.code.Type;
035
036 import static com.sun.tools.javac.code.TypeTags.*;
037
038
039 /**
040 * Utility class for operating on constant expressions.
041 */
042 class Constants {
043
044 /**
045 * Converts a constant in javac's internal representation (in which
046 * boolean, char, byte, short, and int are each represented by an Integer)
047 * into standard representation. Other values (including null) are
048 * returned unchanged.
049 */
050 static Object decodeConstant(Object value, Type type) {
051 if (value instanceof Integer) {
052 int i = ((Integer) value).intValue();
053 switch (type.tag) {
054 case BOOLEAN: return Boolean.valueOf(i != 0);
055 case CHAR: return Character.valueOf((char) i);
056 case BYTE: return Byte.valueOf((byte) i);
057 case SHORT: return Short.valueOf((short) i);
058 }
059 }
060 return value;
061 }
062
063 /**
064 * Returns a formatter for generating the text of constant
065 * expressions. Equivalent to
066 * <tt>getFormatter(new StringBuilder())</tt>.
067 */
068 static Formatter getFormatter() {
069 return new Formatter(new StringBuilder());
070 }
071
072 /**
073 * Returns a formatter for generating the text of constant
074 * expressions. Also generates the text of constant
075 * "pseudo-expressions" for annotations and array-valued
076 * annotation elements.
077 *
078 * @param buf where the expression is written
079 */
080 static Formatter getFormatter(StringBuilder buf) {
081 return new Formatter(buf);
082 }
083
084
085 /**
086 * Utility class used to generate the text of constant
087 * expressions. Also generates the text of constant
088 * "pseudo-expressions" for annotations and array-valued
089 * annotation elements.
090 */
091 static class Formatter {
092
093 private StringBuilder buf; // where the output goes
094
095 private Formatter(StringBuilder buf) {
096 this.buf = buf;
097 }
098
099
100 public String toString() {
101 return buf.toString();
102 }
103
104 /**
105 * Appends a constant whose type is not statically known
106 * by dispatching to the appropriate overloaded append method.
107 */
108 void append(Object val) {
109 if (val instanceof String) {
110 append((String) val);
111 } else if (val instanceof Character) {
112 append((Character) val);
113 } else if (val instanceof Boolean) {
114 append((Boolean) val);
115 } else if (val instanceof Byte) {
116 append((Byte) val);
117 } else if (val instanceof Short) {
118 append((Short) val);
119 } else if (val instanceof Integer) {
120 append((Integer) val);
121 } else if (val instanceof Long) {
122 append((Long) val);
123 } else if (val instanceof Float) {
124 append((Float) val);
125 } else if (val instanceof Double) {
126 append((Double) val);
127 } else if (val instanceof TypeMirror) {
128 append((TypeMirrorImpl) val);
129 } else if (val instanceof EnumConstantDeclaration) {
130 append((EnumConstantDeclarationImpl) val);
131 } else if (val instanceof AnnotationMirror) {
132 append((AnnotationMirrorImpl) val);
133 } else if (val instanceof Collection<?>) {
134 append((Collection<?>) val);
135 } else {
136 appendUnquoted(val.toString());
137 }
138 }
139
140 /**
141 * Appends a string, escaped (as needed) and quoted.
142 */
143 void append(String val) {
144 buf.append('"');
145 appendUnquoted(val);
146 buf.append('"');
147 }
148
149 /**
150 * Appends a Character, escaped (as needed) and quoted.
151 */
152 void append(Character val) {
153 buf.append('\'');
154 appendUnquoted(val.charValue());
155 buf.append('\'');
156 }
157
158 void append(Boolean val) {
159 buf.append(val);
160 }
161
162 void append(Byte val) {
163 buf.append(String.format("0x%02x", val));
164 }
165
166 void append(Short val) {
167 buf.append(val);
168 }
169
170 void append(Integer val) {
171 buf.append(val);
172 }
173
174 void append(Long val) {
175 buf.append(val).append('L');
176 }
177
178 void append(Float val) {
179 if (val.isNaN()) {
180 buf.append("0.0f/0.0f");
181 } else if (val.isInfinite()) {
182 if (val.floatValue() < 0) {
183 buf.append('-');
184 }
185 buf.append("1.0f/0.0f");
186 } else {
187 buf.append(val).append('f');
188 }
189 }
190
191 void append(Double val) {
192 if (val.isNaN()) {
193 buf.append("0.0/0.0");
194 } else if (val.isInfinite()) {
195 if (val.doubleValue() < 0) {
196 buf.append('-');
197 }
198 buf.append("1.0/0.0");
199 } else {
200 buf.append(val);
201 }
202 }
203
204 /**
205 * Appends the class literal corresponding to a type. Should
206 * only be invoked for types that have an associated literal.
207 * e.g: "java.lang.String.class"
208 * "boolean.class"
209 * "int[].class"
210 */
211 void append(TypeMirrorImpl t) {
212 appendUnquoted(t.type.toString());
213 buf.append(".class");
214 }
215
216 /**
217 * Appends the fully qualified name of an enum constant.
218 * e.g: "java.math.RoundingMode.UP"
219 */
220 void append(EnumConstantDeclarationImpl e) {
221 appendUnquoted(e.sym.enclClass() + "." + e);
222 }
223
224 /**
225 * Appends the text of an annotation pseudo-expression.
226 * e.g: "@pkg.Format(linesep='\n')"
227 */
228 void append(AnnotationMirrorImpl anno) {
229 appendUnquoted(anno.toString());
230 }
231
232 /**
233 * Appends the elements of a collection, enclosed within braces
234 * and separated by ", ". Useful for array-valued annotation
235 * elements.
236 */
237 void append(Collection<?> vals) {
238 buf.append('{');
239 boolean first = true;
240 for (Object val : vals) {
241 if (first) {
242 first = false;
243 } else {
244 buf.append(", ");
245 }
246 append(((AnnotationValue) val).getValue());
247 }
248 buf.append('}');
249 }
250
251
252 /**
253 * For each char of a string, append using appendUnquoted(char).
254 */
255 private void appendUnquoted(String s) {
256 for (char c : s.toCharArray()) {
257 appendUnquoted(c);
258 }
259 }
260
261 /**
262 * Appends a char (unquoted), using escapes for those that are not
263 * printable ASCII. We don't know what is actually printable in
264 * the locale in which this result will be used, so ASCII is our
265 * best guess as to the least common denominator.
266 */
267 private void appendUnquoted(char c) {
268 switch (c) {
269 case '\b': buf.append("\\b"); break;
270 case '\t': buf.append("\\t"); break;
271 case '\n': buf.append("\\n"); break;
272 case '\f': buf.append("\\f"); break;
273 case '\r': buf.append("\\r"); break;
274 case '\"': buf.append("\\\""); break;
275 case '\'': buf.append("\\\'"); break;
276 case '\\': buf.append("\\\\"); break;
277 default:
278 if (isPrintableAscii(c)) {
279 buf.append(c);
280 } else {
281 buf.append(String.format("\\u%04x", (int) c));
282 }
283 }
284 }
285
286 /**
287 * Is c a printable ASCII character?
288 */
289 private static boolean isPrintableAscii(char c) {
290 return c >= ' ' && c <= '~';
291 }
292 }
293 }