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: import java.util.Collection;
029:
030: import com.sun.mirror.declaration.*;
031: import com.sun.mirror.type.TypeMirror;
032: import com.sun.tools.apt.mirror.type.TypeMirrorImpl;
033: import com.sun.tools.javac.code.Type;
034:
035: import static com.sun.tools.javac.code.TypeTags.*;
036:
037: /**
038: * Utility class for operating on constant expressions.
039: */
040: class Constants {
041:
042: /**
043: * Converts a constant in javac's internal representation (in which
044: * boolean, char, byte, short, and int are each represented by an Integer)
045: * into standard representation. Other values (including null) are
046: * returned unchanged.
047: */
048: static Object decodeConstant(Object value, Type type) {
049: if (value instanceof Integer) {
050: int i = ((Integer) value).intValue();
051: switch (type.tag) {
052: case BOOLEAN:
053: return Boolean.valueOf(i != 0);
054: case CHAR:
055: return Character.valueOf((char) i);
056: case BYTE:
057: return Byte.valueOf((byte) i);
058: case SHORT:
059: return Short.valueOf((short) i);
060: }
061: }
062: return value;
063: }
064:
065: /**
066: * Returns a formatter for generating the text of constant
067: * expressions. Equivalent to
068: * <tt>getFormatter(new StringBuilder())</tt>.
069: */
070: static Formatter getFormatter() {
071: return new Formatter(new StringBuilder());
072: }
073:
074: /**
075: * Returns a formatter for generating the text of constant
076: * expressions. Also generates the text of constant
077: * "pseudo-expressions" for annotations and array-valued
078: * annotation elements.
079: *
080: * @param buf where the expression is written
081: */
082: static Formatter getFormatter(StringBuilder buf) {
083: return new Formatter(buf);
084: }
085:
086: /**
087: * Utility class used to generate the text of constant
088: * expressions. Also generates the text of constant
089: * "pseudo-expressions" for annotations and array-valued
090: * annotation elements.
091: */
092: static class Formatter {
093:
094: private StringBuilder buf; // where the output goes
095:
096: private Formatter(StringBuilder buf) {
097: this .buf = buf;
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: * For each char of a string, append using appendUnquoted(char).
253: */
254: private void appendUnquoted(String s) {
255: for (char c : s.toCharArray()) {
256: appendUnquoted(c);
257: }
258: }
259:
260: /**
261: * Appends a char (unquoted), using escapes for those that are not
262: * printable ASCII. We don't know what is actually printable in
263: * the locale in which this result will be used, so ASCII is our
264: * best guess as to the least common denominator.
265: */
266: private void appendUnquoted(char c) {
267: switch (c) {
268: case '\b':
269: buf.append("\\b");
270: break;
271: case '\t':
272: buf.append("\\t");
273: break;
274: case '\n':
275: buf.append("\\n");
276: break;
277: case '\f':
278: buf.append("\\f");
279: break;
280: case '\r':
281: buf.append("\\r");
282: break;
283: case '\"':
284: buf.append("\\\"");
285: break;
286: case '\'':
287: buf.append("\\\'");
288: break;
289: case '\\':
290: buf.append("\\\\");
291: break;
292: default:
293: if (isPrintableAscii(c)) {
294: buf.append(c);
295: } else {
296: buf.append(String.format("\\u%04x", (int) c));
297: }
298: }
299: }
300:
301: /**
302: * Is c a printable ASCII character?
303: */
304: private static boolean isPrintableAscii(char c) {
305: return c >= ' ' && c <= '~';
306: }
307: }
308: }
|