/* * This file is part of the X10 project (http://x10-lang.org). * * This file is licensed to You under the Eclipse Public License (EPL); * You may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.opensource.org/licenses/eclipse-1.0.php * * (C) Copyright IBM Corporation 2006-2010. */ package x10.emitter; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import polyglot.types.SemanticException; import polyglot.types.Type; import polyglot.visit.Translator; import x10.types.ConstrainedType; import x10.types.FunctionType; import x10.types.ParameterType; import x10.types.X10ClassDef; import x10.types.X10ClassType; import x10.types.X10FieldInstance; import polyglot.types.TypeSystem; import x10.visit.X10PrettyPrinterVisitor; // constants import static x10.visit.X10PrettyPrinterVisitor.BOX_PRIMITIVES; import static x10.visit.X10PrettyPrinterVisitor.PRINT_TYPE_PARAMS; final public class RuntimeTypeExpander extends Expander { // XTENLANG-2488 public static final boolean useReflectionToGetRTT = true; private final Type at; public RuntimeTypeExpander(Emitter er, Type at) { super(er); if (at instanceof X10ClassType) { X10ClassType ct = (X10ClassType) at; if (ct.isAnonymous()) { if (ct.interfaces().size() > 0) { ct = (X10ClassType) ct.interfaces().get(0); } else if (ct.superClass() != null) { ct = (X10ClassType) ct.superClass(); } } at = ct; } this.at = at; } @Override public String toString() { return "RuntimeTypeExpander{#" + hashCode() + // todo: using hashCode leads to non-determinism in the output of the compiler ", " + at.toString() + "}"; } public static boolean hasConflictingField(X10ClassType ct, Translator tr) { if (!useReflectionToGetRTT) { return false; } TypeSystem xts = tr.typeSystem(); boolean hasConflictingField = false; try { // container is available only if ct is a member if (ct.isMember()) { X10ClassType container = ct.container(); X10FieldInstance fi = xts.findField(container, container, ct.name(), tr.context()); hasConflictingField = fi != null; } } catch (SemanticException e) { // exception means no such field } return hasConflictingField; } public static String getRTT(String qualifiedClassName, boolean hasConflictingField) { String rttString = null; if (useReflectionToGetRTT && hasConflictingField) { rttString = X10PrettyPrinterVisitor.X10_RTT_TYPES + ".<" + qualifiedClassName + "> $RTT(" + qualifiedClassName + ".class)"; } else { rttString = qualifiedClassName + "." + X10PrettyPrinterVisitor.RTT_NAME; } return rttString; } @Override public void expand(Translator tr) { String s = typeof(at); if (s != null) { er.w.write(s); return; } if (at instanceof ParameterType) { ParameterType pt = (ParameterType) at; er.w.write(Emitter.mangleParameterType(pt)); return; } if (at instanceof FunctionType) { FunctionType ct = (FunctionType) at; List<Type> args = ct.argumentTypes(); Type ret = ct.returnType(); // XTENLANG-1102 if (args.size() > 0 || !ret.isVoid()) { er.w.write("x10.rtt.ParameterizedType.make("); printFunRTT(ct); for (Type a : args) { er.w.write(","); new RuntimeTypeExpander(er, a).expand(tr); } if (!ret.isVoid()) { er.w.write(","); new RuntimeTypeExpander(er, ret).expand(tr); } er.w.write(")"); } else { printFunRTT(ct); } return; } if (at instanceof X10ClassType) { X10ClassType ct = (X10ClassType) at; X10ClassDef cd = ct.x10Def(); String pat = Emitter.getJavaRTTRep(cd); // Check for @NativeRep with null RTT class if (pat == null && Emitter.getJavaRep(cd) != null) { er.w.write("new x10.rtt.RuntimeType<Class<?>>("); er.printType(at, 0); er.w.write(".class"); er.w.write(")"); return; } List<Type> classTypeArgs = ct.typeArguments(); if (classTypeArgs == null) classTypeArgs = Collections.<Type>emptyList(); if (pat == null) { String rttString = getRTT(Emitter.mangleQName(cd.fullName()).toString(), hasConflictingField(ct, tr)); // XTENLANG-2118 hack: RTTs for Java types should be looked up using getRTT if (ct.isJavaType()) { rttString = X10PrettyPrinterVisitor.X10_RTT_TYPES + ".getRTT("+Emitter.mangleQName(cd.fullName()).toString()+".class)"; } // XTENLANG-1102 if (ct.isGloballyAccessible() && classTypeArgs.size() == 0) { er.w.write(rttString); } else { er.w.write("x10.rtt.ParameterizedType.make("); er.w.write(rttString); for (int i = 0; i < classTypeArgs.size(); i++) { er.w.write(", "); new RuntimeTypeExpander(er, classTypeArgs.get(i)).expand(tr); } er.w.write(")"); } return; } else { List<ParameterType> classTypeParams = cd.typeParameters(); // if (classTypeParams == null) classTypeParams = Collections.<ParameterType>emptyList(); Iterator<ParameterType> classTypeParamsIter = null; if (classTypeParams != null) { classTypeParamsIter = classTypeParams.iterator(); } Map<String,Object> components = new HashMap<String,Object>(); int i = 0; Object component; String name; component = new TypeExpander(er, ct, PRINT_TYPE_PARAMS | BOX_PRIMITIVES); components.put(String.valueOf(i++), component); components.put("class", component); for (Type at : classTypeArgs) { if (classTypeParamsIter != null) { name = classTypeParamsIter.next().name().toString(); } else { name = null; } // for RTT of Java.array[Comparable[Int]] -> x10.rtt.Types.getRTT(java.lang.Comparable/*<x10.core.Int>*/[].class) int printTypeParamsIfNotNativeRepedToJava = Emitter.isNativeRepedToJava(at) ? 0 : PRINT_TYPE_PARAMS; component = new TypeExpander(er, at, printTypeParamsIfNotNativeRepedToJava); // components.put(String.valueOf(i++), component); // N.B. don't use number index to avoid breaking existing code if (name != null) { components.put(name, component); } component = new TypeExpander(er, at, printTypeParamsIfNotNativeRepedToJava | BOX_PRIMITIVES); components.put(String.valueOf(i++), component); if (name != null) { components.put(name+Emitter.NATIVE_ANNOTATION_BOXED_REP_SUFFIX, component); } component = new RuntimeTypeExpander(er, at); components.put(String.valueOf(i++), component); if (name != null) { components.put(name+Emitter.NATIVE_ANNOTATION_RUNTIME_TYPE_SUFFIX, component); } } er.dumpRegex("NativeRep", components, tr, pat); return; } } if (at instanceof ConstrainedType) { ConstrainedType ct = (ConstrainedType) at; Type base = ct.baseType().get(); new RuntimeTypeExpander(er, base).expand(tr); return; } er.w.write("new x10.rtt.RuntimeType<Class<?>>("); er.printType(at, 0); er.w.write(".class"); er.w.write(")"); } private void printFunRTT(FunctionType ct) { if (ct.returnType().isVoid()) { er.w.write(X10PrettyPrinterVisitor.X10_VOIDFUN_CLASS_PREFIX); } else { er.w.write(X10PrettyPrinterVisitor.X10_FUN_CLASS_PREFIX); } er.w.write("_" + ct.typeParameters().size()); er.w.write("_" + ct.argumentTypes().size()); er.w.write("." + X10PrettyPrinterVisitor.RTT_NAME); } String typeof(Type t) { if (t.isBoolean()) return X10PrettyPrinterVisitor.X10_RTT_TYPES + ".BOOLEAN"; if (t.isChar()) return X10PrettyPrinterVisitor.X10_RTT_TYPES + ".CHAR"; if (t.isNumeric()) { TypeSystem ts = (TypeSystem) er.tr.typeSystem(); if (t.isUnsignedNumeric()) { if (t.isUByte()) return X10PrettyPrinterVisitor.X10_RTT_TYPES + ".UBYTE"; if (t.isUShort()) return X10PrettyPrinterVisitor.X10_RTT_TYPES + ".USHORT"; if (t.isUInt()) return X10PrettyPrinterVisitor.X10_RTT_TYPES + ".UINT"; if (t.isULong()) return X10PrettyPrinterVisitor.X10_RTT_TYPES + ".ULONG"; } else if (t.isSignedNumeric()) { if (t.isByte()) return X10PrettyPrinterVisitor.X10_RTT_TYPES + ".BYTE"; if (t.isShort()) return X10PrettyPrinterVisitor.X10_RTT_TYPES + ".SHORT"; if (t.isInt()) return X10PrettyPrinterVisitor.X10_RTT_TYPES + ".INT"; if (t.isLong()) return X10PrettyPrinterVisitor.X10_RTT_TYPES + ".LONG"; } else { if (t.isFloat()) return X10PrettyPrinterVisitor.X10_RTT_TYPES + ".FLOAT"; if (t.isDouble()) return X10PrettyPrinterVisitor.X10_RTT_TYPES + ".DOUBLE"; } } return null; } }