package ecologylab.bigsemantics.compiler; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ecologylab.bigsemantics.metadata.MetadataClassDescriptor; import ecologylab.bigsemantics.metametadata.MetaMetadata; import ecologylab.bigsemantics.metametadata.MmdCompilerService; import ecologylab.bigsemantics.metametadata.MmdGenericTypeVar; import ecologylab.bigsemantics.metametadata.MmdScope; import ecologylab.generic.HashMapArrayList; import ecologylab.serialization.XMLTools; /** * * @author quyin */ public class DotNetGenericsRenderer { static private Logger logger = LoggerFactory.getLogger(DotNetGenericsRenderer.class); private MmdCompilerService compilerService; public void setMmdCompilerService(MmdCompilerService compilerService) { this.compilerService = compilerService; } /** * * @param mmd * @param scope * @throws IOException */ public void render(Appendable appendable, MetadataClassDescriptor clazz, MmdScope repoScope) throws IOException { MetaMetadata typeMmd = clazz.getDefiningMmd(); if (typeMmd == null && !findTypeMmd(clazz, repoScope)) { return; } typeMmd = clazz.getDefiningMmd(); MmdScope currentScope = typeMmd.getScope(); MetadataClassDescriptor superClazz = (MetadataClassDescriptor) clazz.getSuperClass(); if (superClazz != null && superClazz.getDefiningMmd() == null && !findTypeMmd(superClazz, currentScope)) { return; } String clazzSimpleName = clazz.getDescribedClassSimpleName(); appendable.append(clazzSimpleName); renderDefinitions(appendable, clazz); if (superClazz != null) { appendable.append(" : ").append(superClazz.getDescribedClassSimpleName()); renderBindings(appendable, superClazz, currentScope); } renderWhereClause(appendable, clazz, currentScope); } private boolean findTypeMmd(MetadataClassDescriptor clazz, MmdScope scope) { String superClazzName = clazz.getDescribedClassSimpleName(); String mmdName = XMLTools.getXmlTagName(superClazzName, "Declaration"); Object typeObj = scope.get(mmdName); if (typeObj != null && typeObj instanceof MetaMetadata) { clazz.setDefiningMmd((MetaMetadata) typeObj); return true; } else { logger.warn("Cannot find type mmd for {}", clazz); return false; } } public void renderDefinitions(Appendable appendable, MetadataClassDescriptor clazz) throws IOException { MetaMetadata mmd = clazz.getDefiningMmd(); HashMapArrayList<String, MmdGenericTypeVar> gtvs = mmd.getGenericTypeVarsFromScope(); boolean first = true; for (MmdGenericTypeVar gtv : gtvs) { if (!gtv.isAssignment()) { first = startOrMore(appendable, first); appendable.append(gtv.getName()); } } if (!first) { // there has been at least one generic type vars appendable.append(">"); } } public void renderBindings(Appendable appendable, MetadataClassDescriptor clazz, MmdScope scope) throws IOException { MetaMetadata mmd = clazz.getDefiningMmd(); HashMapArrayList<String, MmdGenericTypeVar> gtvs = mmd.getGenericTypeVarsFromScope(); boolean first = true; for (MmdGenericTypeVar gtv0 : gtvs) { String gtvName = gtv0.getName(); MmdGenericTypeVar gtv = (MmdGenericTypeVar) scope.get(gtvName); if (gtv.isAssignment() || gtv.isRebound()) { first = startOrMore(appendable, first); if (gtv.isAssignment()) { String argName = gtv.getArg(); renderTypeNameRecursively(appendable, gtv, scope, argName); } else { // gtv is rebounding appendable.append(gtvName); } } } if (!first) { // there has been at least one generic type vars appendable.append(">"); } } public void renderWhereClause(Appendable appendable, MetadataClassDescriptor clazz, MmdScope scope) throws IOException { MetaMetadata mmd = clazz.getDefiningMmd(); HashMapArrayList<String, MmdGenericTypeVar> gtvs = mmd.getGenericTypeVarsFromScope(); boolean first = true; for (MmdGenericTypeVar gtv : gtvs) { if (!gtv.isAssignment()) { first = startOrMore(appendable, first, " where ", ", "); appendable.append(gtv.getName()).append(" : "); String extendsName = gtv.getExtendsAttribute(); renderTypeNameRecursively(appendable, gtv, scope, extendsName); } } } public void renderTypeNameRecursively(Appendable appendable, MmdGenericTypeVar gtv, MmdScope scope, String typeName) throws IOException { Object typeObj = scope.get(typeName); if (typeObj instanceof MmdGenericTypeVar) { appendable.append(typeName); } else { // obj is a mmd MetaMetadata typeMmd = (MetaMetadata) typeObj; MetadataClassDescriptor typeClazz = typeMmd.getMetadataClassDescriptor(); addDependency(typeClazz); appendable.append(typeClazz.getDescribedClassSimpleName()); renderBindings(appendable, typeClazz, scope); } } private boolean startOrMore(Appendable appendable, boolean first) throws IOException { return startOrMore(appendable, first, "<", ", "); } private boolean startOrMore(Appendable appendable, boolean first, String start, String delim) throws IOException { if (first) { appendable.append(start); } else { appendable.append(delim); } return false; } private void addDependency(MetadataClassDescriptor clazz) { if (compilerService != null) { compilerService.addCurrentClassDependency(clazz); } } }