001: /*
002: * xtc - The eXTensible Compiler
003: * Copyright (C) 2007 Robert Grimm
004: *
005: * This program is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU General Public License
007: * version 2 as published by the Free Software Foundation.
008: *
009: * This program is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU General Public License for more details.
013: *
014: * You should have received a copy of the GNU General Public License
015: * along with this program; if not, write to the Free Software
016: * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
017: * USA.
018: */
019: package xtc.type;
020:
021: import java.util.ArrayList;
022: import java.util.Collections;
023: import java.util.HashMap;
024: import java.util.HashSet;
025: import java.util.Iterator;
026: import java.util.List;
027: import java.util.Map;
028: import java.util.Set;
029:
030: import xtc.Constants.FuzzyBoolean;
031:
032: import xtc.tree.Locatable;
033:
034: /**
035: * Common type operations for Java ASTs.
036: *
037: * @author Robert Grimm
038: * @version $Revision: 1.6 $
039: */
040: public class JavaAST extends AST {
041:
042: /** The set of Java primitive types. */
043: public static final Set<String> PRIMITIVES;
044:
045: /** The set of Java modifiers. */
046: public static final Set<String> MODIFIERS;
047:
048: /** The set of Java keywords besides primitive types, modifiers, and void. */
049: public static final Set<String> KEYWORDS;
050:
051: static {
052: Set<String> primitives = new HashSet<String>();
053:
054: primitives.add("byte");
055: primitives.add("short");
056: primitives.add("char");
057: primitives.add("int");
058: primitives.add("long");
059: primitives.add("float");
060: primitives.add("double");
061: primitives.add("boolean");
062:
063: PRIMITIVES = Collections.unmodifiableSet(primitives);
064:
065: Set<String> modifiers = new HashSet<String>();
066:
067: modifiers.add("public");
068: modifiers.add("protected");
069: modifiers.add("private");
070: modifiers.add("static");
071: modifiers.add("abstract");
072: modifiers.add("final");
073: modifiers.add("native");
074: modifiers.add("synchronized");
075: modifiers.add("transient");
076: modifiers.add("volatile");
077: modifiers.add("strictfp");
078:
079: MODIFIERS = Collections.unmodifiableSet(primitives);
080:
081: Set<String> keywords = new HashSet<String>();
082:
083: keywords.add("assert");
084: keywords.add("break");
085: keywords.add("case");
086: keywords.add("catch");
087: keywords.add("class");
088: keywords.add("const");
089: keywords.add("continue");
090: keywords.add("default");
091: keywords.add("do");
092: keywords.add("else");
093: keywords.add("enum");
094: keywords.add("extends");
095: keywords.add("finally");
096: keywords.add("for");
097: keywords.add("if");
098: keywords.add("goto");
099: keywords.add("implements");
100: keywords.add("import");
101: keywords.add("instanceof");
102: keywords.add("interface");
103: keywords.add("new");
104: keywords.add("package");
105: keywords.add("return");
106: keywords.add("super");
107: keywords.add("switch");
108: keywords.add("this");
109: keywords.add("throw");
110: keywords.add("throws");
111: keywords.add("try");
112: keywords.add("while");
113:
114: KEYWORDS = Collections.unmodifiableSet(keywords);
115: }
116:
117: // =========================================================================
118:
119: /** The map from Java class names to their classes. */
120: protected Map<String, Class<?>> resolvedTypes;
121:
122: /** Create a new Java AST instance. */
123: public JavaAST() {
124: resolvedTypes = new HashMap<String, Class<?>>();
125: }
126:
127: // =========================================================================
128:
129: public void initialize(boolean hasNode, boolean hasToken,
130: boolean hasFormatting, boolean hasAction) {
131: externToIntern.clear();
132: internToExtern.clear();
133:
134: externToIntern.put("?", Wildcard.TYPE);
135: externToIntern.put("void", VoidT.TYPE);
136: externToIntern.put("Object", ANY);
137: externToIntern.put("java.lang.Object", ANY);
138: externToIntern.put("Character", CHAR);
139: externToIntern.put("java.lang.Character", CHAR);
140: externToIntern.put("String", STRING);
141: externToIntern.put("java.lang.String", STRING);
142: if (hasToken)
143: externToIntern.put("Token", TOKEN);
144: externToIntern.put("xtc.tree.Token", TOKEN);
145: if (hasNode)
146: externToIntern.put("Node", NODE);
147: externToIntern.put("xtc.tree.Node", NODE);
148: externToIntern.put("generic", GENERIC);
149: if (hasNode)
150: externToIntern.put("GNode", NODE);
151: externToIntern.put("xtc.tree.GNode", NODE);
152: if (hasFormatting)
153: externToIntern.put("Formatting", FORMATTING);
154: externToIntern.put("xtc.tree.Formatting", FORMATTING);
155: externToIntern.put("Pair", WILD_LIST);
156: externToIntern.put("xtc.util.Pair", WILD_LIST);
157: if (hasAction)
158: externToIntern.put("Action", WILD_ACTION);
159: externToIntern.put("xtc.util.Action", WILD_ACTION);
160:
161: internToExtern.put("?", "?");
162: internToExtern.put("void", "Void");
163: internToExtern.put("unit", "Void");
164: internToExtern.put("any", "Object");
165: internToExtern.put("char", "Character");
166: internToExtern.put("string", "String");
167: internToExtern.put("token", "Token");
168: internToExtern.put("node", "Node");
169: internToExtern.put("formatting", "Formatting");
170: internToExtern.put("list", "Pair");
171: internToExtern.put("action", "Action");
172: }
173:
174: // ==========================================================================
175:
176: public boolean isVoid(String s) {
177: return "void".equals(s);
178: }
179:
180: public boolean isGenericNode(String s) {
181: return "generic".equals(s);
182: }
183:
184: // ==========================================================================
185:
186: /** The start index for a fully qualified list's element type. */
187: private static final int QLIST_IDX = "xtc.util.Pair<".length();
188:
189: /** The start index for a list's element type. */
190: private static final int LIST_IDX = "Pair<".length();
191:
192: protected Type internList(String s) {
193: if (s.startsWith("xtc.util.Pair<")) {
194: return new InstantiatedT(intern(s.substring(QLIST_IDX, s
195: .length() - 1)), LIST);
196: } else if (s.startsWith("Pair<")) {
197: return new InstantiatedT(intern(s.substring(LIST_IDX, s
198: .length() - 1)), LIST);
199: } else {
200: return ErrorT.TYPE;
201: }
202: }
203:
204: /** The start index for a fully qualified action's element type. */
205: private static final int QACTION_IDX = "xtc.util.Action<".length();
206:
207: /** The start index for an action's element type. */
208: private static final int ACTION_IDX = "Action<".length();
209:
210: protected Type internAction(String s) {
211: if (s.startsWith("xtc.util.Action<")) {
212: return new InstantiatedT(intern(s.substring(QACTION_IDX, s
213: .length() - 1)), ACTION);
214: } else if (s.startsWith("Action<")) {
215: return new InstantiatedT(intern(s.substring(ACTION_IDX, s
216: .length() - 1)), ACTION);
217: } else {
218: return ErrorT.TYPE;
219: }
220: }
221:
222: protected Type internUser(String s) {
223: assert !PRIMITIVES.contains(s);
224: assert !MODIFIERS.contains(s);
225: assert !KEYWORDS.contains(s);
226:
227: final int idx = s.indexOf('<');
228: if (-1 == idx) {
229: return new ClassT(s, null, null, null, null);
230:
231: } else {
232: Type type = new ClassT(s.substring(0, idx), null, null,
233: null, null);
234: String args = s.substring(idx + 1, s.length() - 1);
235:
236: List<Parameter> parameters = new ArrayList<Parameter>();
237: List<Type> arguments = new ArrayList<Type>();
238:
239: int count = 1, start = 0;
240: do {
241: int end = endOfType(args, start);
242:
243: parameters.add(new Parameter("T" + count));
244: arguments.add(intern(args.substring(start, end)));
245:
246: start = end + 1;
247: count++;
248: } while (start < args.length());
249:
250: return new InstantiatedT(arguments, new ParameterizedT(
251: parameters, type));
252: }
253: }
254:
255: /**
256: * Determine the last index (exclusive) of the generic type argument
257: * starting at the specified index.
258: *
259: * @param args The generic type arguments.
260: * @param start The start index.
261: * @return The end index (exclusive).
262: */
263: protected int endOfType(String args, int start) {
264: final int size = args.length();
265:
266: int end = start, nesting = 0;
267: do {
268: char c = args.charAt(end);
269:
270: switch (c) {
271: case '<':
272: nesting++;
273: break;
274: case '>':
275: nesting--;
276: break;
277: case ',':
278: if (0 == nesting)
279: return end;
280: }
281:
282: end++;
283: } while (end < size);
284:
285: return end;
286: }
287:
288: // ==========================================================================
289:
290: protected String externList(Type type) {
291: return "Pair<" + extern(getArgument(type)) + ">";
292: }
293:
294: protected String externAction(Type type) {
295: return "Action<" + extern(getArgument(type)) + ">";
296: }
297:
298: protected String externUser(Type type) {
299: if (type.hasInstantiated() || type.hasParameterized()) {
300: StringBuilder buf = new StringBuilder();
301:
302: buf.append(extern(type.resolve()));
303: buf.append('<');
304:
305: Iterator<? extends Type> iter = type.hasInstantiated() ? type
306: .toInstantiated().getArguments().iterator()
307: : type.toParameterized().getParameters().iterator();
308: do {
309: buf.append(extern(iter.next()));
310: if (iter.hasNext())
311: buf.append(',');
312: } while (iter.hasNext());
313:
314: buf.append('>');
315: return buf.toString();
316:
317: } else {
318: if (!type.resolve().isClass())
319: System.out.println(type);
320:
321: return type.resolve().toClass().getQName();
322: }
323: }
324:
325: // ==========================================================================
326:
327: protected FuzzyBoolean hasLocationUser(Type type) {
328: final Class<?> k = resolve(type.resolve().toClass().getQName());
329:
330: if ((null == k) || Object.class.equals(k)) {
331: return FuzzyBoolean.MAYBE;
332: } else if (Locatable.class.isAssignableFrom(k)) {
333: return FuzzyBoolean.TRUE;
334: } else {
335: return FuzzyBoolean.FALSE;
336: }
337: }
338:
339: // ==========================================================================
340:
341: protected Type unifyUser(Type t1, Type t2, boolean strict) {
342: Type r1 = t1.resolve(), r2 = t2.resolve();
343:
344: if (r1.isClass()
345: && r2.isClass()
346: && r1.toClass().getQName().equals(
347: r2.toClass().getQName())) {
348: return t1;
349: } else if (strict) {
350: return ErrorT.TYPE;
351: } else {
352: return ANY;
353: }
354: }
355:
356: // ==========================================================================
357:
358: /**
359: * Resolve the specified type name to its class. This method relies
360: * on the {@link #importedTypes} and {@link #importedModules} data
361: * structures to map incomplete type names to fully qualified type
362: * names. It caches results in the {@link #resolvedTypes} data
363: * structure to speed up future resolutions.
364: *
365: * @param name The type name.
366: * @return The corresponding class or <code>null</code> if the name
367: * cannot be resolved.
368: */
369: public Class<?> resolve(String name) {
370: if (resolvedTypes.containsKey(name))
371: return resolvedTypes.get(name);
372:
373: Class<?> k = null;
374: if (importedTypes.containsKey(name)) {
375: // The type has been explicitly imported.
376: try {
377: k = Class.forName(importedTypes.get(name));
378: } catch (ClassNotFoundException x) {
379: // Ignore.
380: }
381:
382: } else {
383: // The type should have been implicitly imported.
384: for (String module : importedModules) {
385: try {
386: k = Class.forName(module + name);
387: break;
388: } catch (ClassNotFoundException x) {
389: // Ignore.
390: }
391: }
392:
393: if (null == k) {
394: // As a last resort, try the name directly.
395: try {
396: k = Class.forName(name);
397: } catch (ClassNotFoundException x) {
398: // Ignore.
399: }
400: }
401: }
402:
403: // Remember the resolved class.
404: resolvedTypes.put(name, k);
405: return k;
406: }
407:
408: }
|