001: /**************************************************************************/
002: /* N I C E */
003: /* A high-level object-oriented research language */
004: /* (c) Daniel Bonniot 2000 */
005: /* */
006: /* This program is free software; you can redistribute it and/or modify */
007: /* it under the terms of the GNU General Public License as published by */
008: /* the Free Software Foundation; either version 2 of the License, or */
009: /* (at your option) any later version. */
010: /* */
011: /**************************************************************************/package nice.tools.code;
012:
013: import mlsub.typing.*;
014: import bossa.util.Debug;
015: import bossa.util.Internal;
016: import nice.tools.typing.PrimitiveType;
017:
018: import gnu.bytecode.*;
019: import gnu.expr.*;
020:
021: import java.util.*;
022:
023: /**
024: Conversion between Nice and bytecode types.
025:
026: @version $Date: 2005/01/14 18:53:53 $
027: @author Daniel Bonniot
028: */
029:
030: public final class Types {
031: /****************************************************************
032: * Mapping TCs to gnu.bytecode.Types
033: ****************************************************************/
034:
035: private static HashMap tcToGBType;
036:
037: public static void set(TypeConstructor tc, Type type) {
038: tcToGBType.put(tc, type);
039: }
040:
041: private static void set(Monotype m, Type type) {
042: tcToGBType.put(m, type);
043: }
044:
045: public static Type get(TypeConstructor tc) {
046: return (Type) tcToGBType.get(tc);
047: }
048:
049: public static Type get(Monotype m) {
050: return (Type) tcToGBType.get(m);
051: }
052:
053: public static Type javaType(TypeConstructor tc) {
054: Type res = get(tc);
055: if (res == null)
056: return gnu.bytecode.Type.pointer_type;
057: else
058: return res;
059: }
060:
061: /**
062: Prepare <tt>m</tt> to be given a precise bytecode type if possible.
063:
064: Be careful:
065: Type components of <tt>m</tt> must be valid.
066: That is, englobing constraints must be asserted.
067: */
068: public static void setBytecodeType(Monotype m) {
069: m = nice.tools.typing.Types.equivalent(m);
070:
071: if (m instanceof mlsub.typing.TupleType)
072: setBytecodeType(((mlsub.typing.TupleType) m)
073: .getComponents());
074:
075: TypeConstructor tc = m.head();
076: if (tc == null)
077: return;
078:
079: TypeConstructor rigidTC;
080: if (tc == PrimitiveType.arrayTC)
081: rigidTC = tc;
082: else {
083: if (Types.get(tc) != null)
084: // OK, nothing to do
085: return;
086:
087: // We try to approximate a polymorphic type by a monomorphic one.
088: // So any instance will do, but a lower one is better.
089: rigidTC = Typing.lowestInstance(tc);
090:
091: if (rigidTC == null)
092: // We don't know
093: return;
094: }
095:
096: /* Only for arrays, we are interested in the components too.
097: It that case we associate the bytecode type to the Nice monotype,
098: not to the type constructor.
099: */
100: if (rigidTC == PrimitiveType.arrayTC) {
101: Monotype param = ((MonotypeConstructor) m).getTP()[0];
102:
103: setBytecodeType(param);
104: Types.set(m, SpecialTypes.array(javaTypeOrNull(param)));
105: } else
106: Types.set(tc, Types.get(rigidTC));
107: }
108:
109: /**
110: Iter setBytecodeType.
111: */
112: public static void setBytecodeType(Monotype[] ms) {
113: for (int i = 0; i < ms.length; i++)
114: setBytecodeType(ms[i]);
115: }
116:
117: /****************************************************************
118: * Mapping monotypes to java types
119: ****************************************************************/
120:
121: /**
122: Return the bytecode type used to represent objects of this type.
123:
124: You might want use the {@link #setBytecodeType(mlsub.typing.Monotype)}
125: method before to make result more precise.
126: */
127: public static Type javaType(Monotype m) {
128: Type res = javaTypeOrNull(m);
129: if (res != null)
130: return res;
131: else
132: return Type.pointer_type;
133: }
134:
135: /**
136: @return the java type of a monotype, or null when no precise type can
137: be given (for an unconstrained type parameter, for instance).
138:
139: It is useful to distinguish the "no precise type" from the Object type,
140: in the case where Object is explicitely mentioned in the source,
141: because Object[] is Object[] in bytecode, while T[] is Object.
142: */
143: private static Type javaTypeOrNull(Monotype m) {
144: Type res = rawJavaType(nice.tools.typing.Types.equivalent(m));
145: if (res == null)
146: return null;
147:
148: boolean maybe = nice.tools.typing.Types.isMaybe(m.equivalent());
149: if (maybe)
150: return equivalentObjectType(res);
151: else
152: return res;
153: }
154:
155: private static Type rawJavaType(Monotype m) {
156: Type res = get(m);
157: if (res != null)
158: return res;
159:
160: if (m instanceof mlsub.typing.TupleType)
161: return new TupleType(javaType(((mlsub.typing.TupleType) m)
162: .getComponents()));
163:
164: if (m instanceof FunType)
165: return gnu.expr.Compilation.typeProcedure;
166:
167: if (m == TopMonotype.instance)
168: return Type.pointer_type;
169:
170: if (!(m instanceof MonotypeConstructor))
171: return null;
172:
173: MonotypeConstructor mc = (MonotypeConstructor) m;
174: TypeConstructor tc = mc.getTC();
175:
176: if (tc == PrimitiveType.arrayTC)
177: return SpecialTypes.array(javaTypeOrNull(mc.getTP()[0]));
178: else
179: return javaType(tc);
180: }
181:
182: public static Type[] javaType(Monotype[] ms) {
183: if (ms == null)
184: return null;
185:
186: Type[] res = new Type[ms.length];
187: for (int i = 0; i < ms.length; i++)
188: res[i] = javaType(ms[i]);
189: return res;
190: }
191:
192: public static Type javaType(Polytype t) {
193: return javaType(t.getMonotype());
194: }
195:
196: /**
197: @return the most precise bytecode type able to store values of the given
198: Nice types
199: */
200: public static Type lowestCommonSupertype(Monotype[] types) {
201: Type res = javaType(types[0]);
202: for (int i = 1; res != null && i < types.length; i++)
203: res = Type.lowestCommonSuperType(res, javaType(types[i]));
204:
205: if (res == null)
206: return Type.pointer_type;
207: else
208: return res;
209: }
210:
211: static Type lowestCommonSupertype(Type[] types) {
212: Type res = types[0];
213: for (int i = 1; res != null && i < types.length; i++)
214: res = Type.lowestCommonSuperType(res, types[i]);
215:
216: if (res == null)
217: return Type.pointer_type;
218: else
219: return res;
220: }
221:
222: public static Type lowestUpperBound(Expression[] exps) {
223: if (exps.length == 0)
224: return Type.pointer_type;
225:
226: // Start with the minimal type.
227: Type res = Type.neverReturnsType;
228:
229: for (int i = 0; i < exps.length; i++) {
230: res = Type.lowestCommonSuperType(res, exps[i].getType());
231:
232: if (res == null)
233: return Type.pointer_type;
234: }
235:
236: return res;
237: }
238:
239: public static Type componentType(ArrayType type, int rank) {
240: if (type instanceof TupleType)
241: return ((TupleType) type).componentTypes[rank];
242:
243: return type.getComponentType();
244: }
245:
246: /****************************************************************
247: * Converting a bytecode type (coming from reflection for instance)
248: * into a Nice type.
249: * Used for automatic declaration of java methods.
250: ****************************************************************/
251:
252: public static TypeConstructor typeConstructor(Type javaType)
253: throws NotIntroducedClassException {
254: TypeConstructor tc = bossa.syntax.Node.globalTypeScopeLookup(
255: javaType.getName(), null);
256:
257: if (tc == null) {
258: Internal.warning(javaType + " is not known");
259: throw new NotIntroducedClassException(tc);
260: }
261:
262: if (tc.getId() == -1)
263: throw new NotIntroducedClassException(tc);
264:
265: return tc;
266: }
267:
268: public static Monotype[] monotype(Type[] javaTypes,
269: TypeVariable[] typeVariables, TypeSymbol[] niceTypeVariables)
270: throws ParametricClassException,
271: NotIntroducedClassException {
272: int len = javaTypes.length;
273: Monotype[] res = new Monotype[len];
274: for (int i = 0; i < len; i++)
275: res[i] = monotype(javaTypes[i], true, typeVariables,
276: niceTypeVariables);
277: return res;
278: }
279:
280: public static Monotype monotype(Type javaType, boolean sure)
281: throws ParametricClassException,
282: NotIntroducedClassException {
283: return monotype(javaType, sure, null, null);
284: }
285:
286: /**
287: Special version for use in Import.java,
288: it always checks whether nullness info may be added.
289: */
290: public static Monotype monotype(Type javaType, boolean sure,
291: TypeVariable[] typeVariables, TypeSymbol[] niceTypeVariables)
292: throws ParametricClassException,
293: NotIntroducedClassException {
294: Monotype res = getMonotype(javaType, typeVariables,
295: niceTypeVariables);
296: //primitivetypes and typevariables should not get nullness info
297: if (javaType instanceof ObjectType
298: && !(javaType instanceof TypeVariable)) {
299: if (sure)
300: return nice.tools.typing.Types.sureMonotype(res);
301: else
302: return nice.tools.typing.Types.maybeMonotype(res);
303: }
304: return res;
305: }
306:
307: private static Monotype getMonotype(Type javaType,
308: TypeVariable[] typeVariables, TypeSymbol[] niceTypeVariables)
309: throws ParametricClassException,
310: NotIntroducedClassException {
311: if (javaType.isVoid())
312: return PrimitiveType.voidType;
313: if (javaType == SpecialTypes.intType)
314: return PrimitiveType.intType;
315: if (javaType == SpecialTypes.booleanType)
316: return PrimitiveType.boolType;
317: if (javaType == SpecialTypes.charType)
318: return PrimitiveType.charType;
319: if (javaType == SpecialTypes.byteType)
320: return PrimitiveType.byteType;
321: if (javaType == SpecialTypes.shortType)
322: return PrimitiveType.shortType;
323: if (javaType == SpecialTypes.longType)
324: return PrimitiveType.longType;
325: if (javaType == SpecialTypes.floatType)
326: return PrimitiveType.floatType;
327: if (javaType == SpecialTypes.doubleType)
328: return PrimitiveType.doubleType;
329:
330: if (javaType instanceof ArrayType)
331: return new MonotypeConstructor(PrimitiveType.arrayTC,
332: new Monotype[] { monotype(((ArrayType) javaType)
333: .getComponentType(), true, typeVariables,
334: niceTypeVariables) });
335:
336: if (javaType instanceof ParameterizedType) {
337: ParameterizedType p = (ParameterizedType) javaType;
338: try {
339: return new MonotypeConstructor(typeConstructor(p.main),
340: monotype(p.parameters, typeVariables,
341: niceTypeVariables));
342: } catch (BadSizeEx ex) {
343: // This can happen, at least if a bytecode method is using
344: // a generic class incorrectly.
345: throw new ParametricClassException(javaType.toString());
346: }
347: }
348:
349: if (javaType instanceof TypeVariable) {
350: if (typeVariables != null)
351: for (int i = 0; i < typeVariables.length; i++)
352: if (typeVariables[i] == javaType)
353: return (Monotype) niceTypeVariables[i];
354:
355: Internal.warning("Type variable " + javaType.getName()
356: + " is not known");
357: throw new NotIntroducedClassException(null);
358: }
359:
360: if (javaType == Type.pointer_type)
361: return TopMonotype.instance;
362:
363: TypeConstructor tc = bossa.syntax.Node.globalTypeScopeLookup(
364: javaType.getName(), null);
365:
366: if (tc == null) {
367: Internal.warning(javaType.getName() + " is not known");
368: throw new NotIntroducedClassException(tc);
369: }
370:
371: if (tc.getId() == -1)
372: throw new NotIntroducedClassException(tc);
373:
374: try {
375: return nice.tools.typing.Types.unknownArgsMonotype(tc);
376: } catch (BadSizeEx ex) {
377: throw new ParametricClassException(tc.toString());
378: }
379: }
380:
381: /**
382: Thrown when one tries to get a monotype
383: for a class defined to have type parameters.
384: The rationale is that methods using that class
385: should not be fetched, as the compiler cannot
386: guess the correct type parameters.
387: */
388: public static class ParametricClassException extends Exception {
389: ParametricClassException(String message) {
390: super (message);
391: }
392: }
393:
394: /**
395: Thrown when the type would contain elements that
396: are not valid for typechecking.
397: This happens for native classes that are discovered
398: after the context rigidification (due to ClassExp expressions).
399: */
400: public static class NotIntroducedClassException extends Exception {
401: /** The invalid type element. */
402: public TypeSymbol symbol;
403:
404: NotIntroducedClassException(TypeSymbol symbol) {
405: this .symbol = symbol;
406: }
407: }
408:
409: /****************************************************************
410: * Converting string to gnu.bytecode.Type
411: ****************************************************************/
412:
413: public static final gnu.bytecode.Type type(
414: bossa.syntax.LocatedString name) {
415: return type(name.toString(), name.location());
416: }
417:
418: public static final gnu.bytecode.Type type(String s,
419: bossa.util.Location loc) {
420: if (s.length() == 0)
421: return null;
422:
423: if (s.charAt(0) == '[') {
424: Type res = type(s.substring(1), loc);
425: if (res == null)
426: return null;
427: else
428: return SpecialArray.create(res);
429: }
430:
431: if (s.equals("void"))
432: return SpecialTypes.voidType;
433: if (s.equals("boolean"))
434: return SpecialTypes.booleanType;
435: if (s.equals("byte"))
436: return SpecialTypes.byteType;
437: if (s.equals("short"))
438: return SpecialTypes.shortType;
439: if (s.equals("int"))
440: return SpecialTypes.intType;
441: if (s.equals("long"))
442: return SpecialTypes.longType;
443: if (s.equals("char"))
444: return SpecialTypes.charType;
445: if (s.equals("float"))
446: return SpecialTypes.floatType;
447: if (s.equals("double"))
448: return SpecialTypes.doubleType;
449:
450: return TypeImport.lookup(s, loc);
451: }
452:
453: /**
454: The type is not necessarily fully qualified.
455: */
456: public static final gnu.bytecode.Type typeRepresentationToBytecode(
457: String type, bossa.util.Location loc) {
458: if (type.charAt(0) == '[') {
459: Type res = typeRepresentationToBytecode(type.substring(1),
460: loc);
461: if (res == null)
462: return null;
463: else
464: return SpecialArray.create(res);
465: }
466:
467: if (type.equals("Object") || type.equals("java.lang.Object"))
468: return Type.pointer_type;
469:
470: TypeConstructor sym = bossa.syntax.Node.globalTypeScopeLookup(
471: type, loc);
472:
473: return get(sym);
474: }
475:
476: /****************************************************************
477: * Manipulating bytecode types
478: ****************************************************************/
479:
480: public static Type equivalentObjectType(Type t) {
481: if (t instanceof ObjectType)
482: return (ObjectType) t;
483:
484: if (t == Type.boolean_type)
485: return Type.boolean_ctype;
486: else if (t == Type.double_type || t == Type.float_type
487: || t == Type.long_type || t == Type.int_type
488: || t == Type.short_type || t == Type.byte_type)
489: return PrimType.number_type;
490: else if (t == Type.char_type)
491: return PrimType.char_ctype;
492: // Fix-up.
493: else if (t == Type.void_type)
494: return PrimType.void_type;
495:
496: bossa.util.Internal.error("Equivalent type for " + t
497: + " is not defined yet");
498: return null;
499: }
500:
501: /****************************************************************
502: * Reset the state for a new compilation.
503: ****************************************************************/
504:
505: public static void reset() {
506: tcToGBType = new HashMap();
507: Import.reset();
508: }
509:
510: /**
511: * Test if use of a TypeConstructor is legal within a given package
512: */
513: public static boolean legalAccess(TypeConstructor tc,
514: String packageName) {
515: Type type = get(tc);
516: if (!(type instanceof ClassType))
517: return true;
518:
519: return Access.legal((ClassType) type, packageName);
520: }
521: }
|