package ecologylab.bigsemantics.compiler; import static ecologylab.translators.net.DotNetTranslationConstants.SPACE; import java.io.IOException; import java.util.Collection; import java.util.List; import java.util.Map; import ecologylab.bigsemantics.html.utils.StringBuilderUtils; import ecologylab.bigsemantics.metadata.MetadataClassDescriptor; import ecologylab.bigsemantics.metadata.MetadataFieldDescriptor; import ecologylab.bigsemantics.metametadata.MetaMetadata; import ecologylab.bigsemantics.metametadata.MetaMetadataCompositeField; import ecologylab.bigsemantics.metametadata.MetaMetadataField; import ecologylab.bigsemantics.metametadata.MetaMetadataNestedField; import ecologylab.bigsemantics.metametadata.MetaMetadataRepository; import ecologylab.bigsemantics.metametadata.MmdCompilerService; import ecologylab.bigsemantics.metametadata.MmdGenericTypeVar; import ecologylab.bigsemantics.metametadata.MmdScope; import ecologylab.bigsemantics.metametadata.declarations.MetaMetadataFieldDeclaration; import ecologylab.bigsemantics.namesandnums.SemanticsNames; import ecologylab.generic.Debug; import ecologylab.generic.StringTools; import ecologylab.serialization.ClassDescriptor; import ecologylab.serialization.FieldDescriptor; import ecologylab.serialization.MetaInformation; import ecologylab.serialization.SimplTypesScope; import ecologylab.serialization.annotations.simpl_descriptor_classes; import ecologylab.serialization.annotations.simpl_inherit; import ecologylab.translators.net.DotNetTranslationException; import ecologylab.translators.net.DotNetTranslator; public class MetaMetadataDotNetTranslator extends DotNetTranslator implements MmdCompilerService { public static final String SCALAR_GETTER_SETTER_SUFFIX = "Metadata"; private static String[] metaMetadataDefaultImports = { "Ecologylab.BigSemantics.MetaMetadataNS", "Ecologylab.BigSemantics.MetadataNS.Builtins", }; public MetaMetadataDotNetTranslator() { genericsRender.setMmdCompilerService(this); for (String importTarget : metaMetadataDefaultImports) { addGlobalDependency(importTarget); } // addLibraryTScopeDependency("ecologylab.semantics.metadata.builtins"); } private static String csharpNSMetadata = "Ecologylab.BigSemantics.Metadata"; private static String csharpNSMetadataNS = "Ecologylab.BigSemantics.MetadataNS"; private static String csharpNSMetaMetadata = "Ecologylab.BigSemantics.Metametadata"; private static String csharpNSMetaMetadataNS = "Ecologylab.BigSemantics.MetaMetadataNS"; private static String csharpNSLibraryDot = "Ecologylab.BigSemantics.Generated.Library."; private DotNetGenericsRenderer genericsRender = new DotNetGenericsRenderer(); protected String javaPackage2CSharpNamespace(String packageName) { String ns = super.javaPackage2CSharpNamespace(packageName); ns = ns.replace("Ecologylab.Bigsemantics.", "Ecologylab.BigSemantics."); ns = fixNameCollisions(ns); if (ns.startsWith(csharpNSMetadata) && !ns.startsWith(csharpNSMetadataNS)) { ns = ns.replace(csharpNSMetadata, csharpNSMetadataNS); return ns; } if (ns.startsWith(csharpNSMetaMetadata) && !ns.startsWith(csharpNSMetaMetadataNS)) { ns = ns.replace(csharpNSMetaMetadata, csharpNSMetaMetadataNS); return ns; } if (ns.startsWith(csharpNSLibraryDot)) { if (!ns.endsWith("NS")) return ns + "NS"; } return ns; } private String fixNameCollisions(String ns) { String[] intermediateNames = ns.split("\\."); for (int i = 0; i < intermediateNames.length; ++i) { String intermediateName = intermediateNames[i]; if (isSimpleClassName(intermediateName) || isSimpleClassName(intermediateName + "Declaration")) { intermediateNames[i] = intermediateName + "NS"; } } ns = StringTools.join(".", intermediateNames); return ns; } private static final String csharpSemanticsNamespacePrefix = "Ecologylab.BigSemantics."; private static final String csharpGeneratedSemanticsNamespacePrefix = "Ecologylab.BigSemantics.Generated."; @Override protected String[] getGeneratedClassFileDirStructure(ClassDescriptor inputClass) { String packageName = inputClass.getDescribedClassPackageName(); String[] result = getGeneratedClassFileDirStructure(packageName); String csharpNamespace = javaPackage2CSharpNamespace(packageName); inputClass.setDescribedClassPackageName(csharpNamespace); return result; } @Override protected String[] getGeneratedClassFileDirStructure(String classPackageName) { String csharpNamespace = javaPackage2CSharpNamespace(classPackageName); csharpNamespace = csharpNamespace.replace("Ecologylab.Bigsemantics.", "Ecologylab.BigSemantics."); if (csharpNamespace.startsWith(csharpGeneratedSemanticsNamespacePrefix)) { String dirStructureStr = csharpNamespace.substring(csharpGeneratedSemanticsNamespacePrefix.length()); return dirStructureStr.split(PACKAGE_NAME_SEPARATOR); } else if (csharpNamespace.startsWith(csharpSemanticsNamespacePrefix)) { String dirStructureStr = csharpNamespace.substring(csharpSemanticsNamespacePrefix.length()); return dirStructureStr.split(PACKAGE_NAME_SEPARATOR); } else { return super.getGeneratedClassFileDirStructure(classPackageName); } } @Override protected void appendClassMetaInformationHook(ClassDescriptor classDesc, Appendable appendable) { MetaMetadata definingMmd = ((MetadataClassDescriptor) classDesc).getDefiningMmd(); if (definingMmd.isRootMetaMetadata()) { List<MetaInformation> metaInfo = classDesc.getMetaInformation(); metaInfo.add(new MetaInformation(simpl_descriptor_classes.class, true, MetadataClassDescriptor.class, MetadataFieldDescriptor.class)); metaInfo.add(new MetaInformation(simpl_inherit.class)); this.addCurrentClassDependency("Simpl.Serialization.Attributes"); this.addCurrentClassDependency(MetadataClassDescriptor.class.getPackage().getName()); this.addCurrentClassDependency(MetadataFieldDescriptor.class.getPackage().getName()); } super.appendClassMetaInformationHook(classDesc, appendable); } @Override protected void superClassHook(ClassDescriptor inputClass, Appendable appendable) throws IOException { MetaMetadata definingMmd = ((MetadataClassDescriptor) inputClass).getDefiningMmd(); if (definingMmd.isRootMetaMetadata()) { // TODO we are moving away from Prism stuffs ... // appendable.append(" : NotificationObject"); // addCurrentClassDependency("Microsoft.Practices.Prism.ViewModel"); } } @Override protected void appendClassGenericTypeVariables(Appendable appendable, ClassDescriptor inputClass) throws IOException { genericsRender.renderDefinitions(appendable, (MetadataClassDescriptor) inputClass); } @Override protected void appendSuperClassGenericTypeVariables(Appendable appendable, ClassDescriptor inputClass) throws IOException { MetadataClassDescriptor clazz = (MetadataClassDescriptor) inputClass; MmdScope currentScope = clazz.getDefiningMmd().getScope(); MetadataClassDescriptor superClazz = (MetadataClassDescriptor) inputClass.getSuperClass(); genericsRender.renderBindings(appendable, superClazz, currentScope); genericsRender.renderWhereClause(appendable, clazz, currentScope); } public void appendGenericTypeVarExtends(Appendable appendable, Collection<MmdGenericTypeVar> mmdGenericTypeVars, MetaMetadataRepository repository) throws IOException { if (mmdGenericTypeVars != null && mmdGenericTypeVars.size() > 0) { boolean first = true; for (MmdGenericTypeVar mmdGenericTypeVar : mmdGenericTypeVars) { String varName = mmdGenericTypeVar.getName(); String extendsName = mmdGenericTypeVar.getExtendsAttribute(); String argName = mmdGenericTypeVar.getArg(); if (varName != null && extendsName != null && argName == null) { if (first) { appendable.append("<"); first = false; } else appendable.append(", "); MetaMetadata mmd = mmdGenericTypeVar.getResolvedExtendsMmd(); appendable.append(mmd.getMetadataClassDescriptor().getDescribedClassSimpleName()); appendGenericTypeVarExtends(appendable, mmdGenericTypeVar.getNestedGenericTypeVars(), repository); } } if (!first) appendable.append(">"); } } @Override protected void appendField(ClassDescriptor context, FieldDescriptor fieldDescriptor, Appendable appendable) throws DotNetTranslationException, IOException { ((MetadataFieldDescriptor) fieldDescriptor).setCompilerService(this); super.appendField(context, fieldDescriptor, appendable); } @Override protected void appendFieldGenericTypeVars(ClassDescriptor contextCd, FieldDescriptor fieldDescriptor, Appendable appendable) throws IOException { if (fieldDescriptor.getCollectionType() != null) return; // should have been handled by MetadataFieldDescriptor.getJavaType() MetadataFieldDescriptor mdFD = (MetadataFieldDescriptor) fieldDescriptor; MetaMetadataField field = mdFD.getDefiningMmdField(); if (field instanceof MetaMetadataNestedField) { MetaMetadataNestedField nestedField = (MetaMetadataNestedField) field; MetaMetadataRepository repository = nestedField.getRepository(); appendGenericTypeVarParameterizations(appendable, (List<MmdGenericTypeVar>) nestedField .getGenericTypeVarsList(), repository); } } public void appendGenericTypeVarDefinitions(Appendable appendable, Collection<MmdGenericTypeVar> mmdGenericTypeVars, MetaMetadataRepository repository) throws IOException { if (mmdGenericTypeVars != null && mmdGenericTypeVars.size() > 0) { boolean first = true; for (MmdGenericTypeVar mmdGenericTypeVar : mmdGenericTypeVars) { String varName = mmdGenericTypeVar.getName(); String extendsName = mmdGenericTypeVar.getExtendsAttribute(); String argName = mmdGenericTypeVar.getArg(); if (varName != null && extendsName != null && argName == null) { if (!StringTools.isUpperCase(varName)) { Debug.warning(MmdGenericTypeVar.class, "We recommend capital letters for generic variable names!"); } if (first) { appendable.append("<"); first = false; } else appendable.append(", "); appendable.append(varName); //appendGenericTypeVarParameterizations(appendable, mmdGenericTypeVar.getNestedGenericTypeVars(), repository); } } if (!first) appendable.append(">"); } } public void appendGenericTypeVarWhereClause(Appendable appendable, Collection<MmdGenericTypeVar> mmdGenericTypeVars, MetaMetadataRepository repository) throws IOException { if (mmdGenericTypeVars != null && mmdGenericTypeVars.size() > 0) { boolean first = true; for (MmdGenericTypeVar mmdGenericTypeVar : mmdGenericTypeVars) { String varName = mmdGenericTypeVar.getName(); String extendsName = mmdGenericTypeVar.getExtendsAttribute(); String argName = mmdGenericTypeVar.getArg(); if (varName != null && extendsName != null && argName == null) { if (!StringTools.isUpperCase(varName)) { Debug.warning(MmdGenericTypeVar.class, "We recommend capital letters for generic variable names!"); } if (first) { appendable.append(" where "); first = false; } else appendable.append(", "); appendable .append(varName) .append(" : ") .append(MmdGenericTypeVar.getMdClassNameFromMmdOrNoChange(extendsName, repository, this)); appendGenericTypeVarParameterizations(appendable, mmdGenericTypeVar.getNestedGenericTypeVars(), repository); } } } } @Override public void appendGenericTypeVarParameterizations(Appendable appendable, Collection<MmdGenericTypeVar> mmdGenericTypeVars, MetaMetadataRepository repository) throws IOException { if (mmdGenericTypeVars != null && mmdGenericTypeVars.size() > 0) { boolean first = true; for (MmdGenericTypeVar mmdGenericTypeVar : mmdGenericTypeVars) { String varName = mmdGenericTypeVar.getName(); String extendsName = mmdGenericTypeVar.getExtendsAttribute(); String argName = mmdGenericTypeVar.getArg(); if (argName != null && ((varName == null && extendsName == null) || varName != null)) { if (first) { appendable.append("<"); first = false; } else appendable.append(", "); appendable.append(MmdGenericTypeVar.getMdClassNameFromMmdOrNoChange(argName, repository, this)); int firstIndexOf = appendable.toString().lastIndexOf("<"); appendGenericTypeVarParameterizations(appendable, mmdGenericTypeVar.getNestedGenericTypeVars(), repository); if (appendable.toString().lastIndexOf("<") == firstIndexOf) appendGenericTypeVarExtends(appendable, mmdGenericTypeVar.getNestedGenericTypeVars(), repository); } } if (!first) appendable.append(">"); } } @Override protected void appendFieldMetaInformationHook(ClassDescriptor contextCd, FieldDescriptor fieldDesc, Appendable appendable) throws IOException { super.appendFieldMetaInformationHook(contextCd, fieldDesc, appendable); MetadataFieldDescriptor fd = (MetadataFieldDescriptor) fieldDesc; List<MetaInformation> metaInfoBuf = fd.getMetaInformation(); MetaMetadataField f = fd.getDefiningMmdField(); f.addAdditionalMetaInformation(metaInfoBuf, this); } @Override protected void appendConstructorHook(ClassDescriptor inputClass, Appendable appendable, String classSimpleName) throws IOException { super.appendConstructorHook(inputClass, appendable, classSimpleName); MetaMetadata definingMmd = ((MetadataClassDescriptor) inputClass).getDefiningMmd(); if (definingMmd.isRootMetaMetadata()) return; appendable.append("\n"); appendable.append("\t\tpublic ").append(inputClass.getDescribedClassSimpleName()) .append("(MetaMetadataCompositeField mmd) : base(mmd) { }\n"); appendable.append("\n"); addCurrentClassDependency(MetaMetadataCompositeField.class.getPackage().getName()); } @Override protected void appendGettersAndSettersHook(ClassDescriptor context, FieldDescriptor fieldDescriptor, Appendable appendable) { super.appendGettersAndSettersHook(context, fieldDescriptor, appendable); // don't need this right now. } @Override protected void generateLibraryTScopeGetter(Appendable appendable, SimplTypesScope tScope) throws IOException { CompilerConfig cconfig = (CompilerConfig) config; if (cconfig.getBuiltinDeclarationScopeName() == null) { appendable.append(SINGLE_LINE_BREAK); appendable.append(DOUBLE_TAB); appendable.append(PUBLIC); appendable.append(SPACE); appendable.append(STATIC); appendable.append(SPACE); appendable.append(DOTNET_TRANSLATION_SCOPE); appendable.append(SPACE); appendable.append("Get"); appendable.append(OPENING_BRACE); appendable.append(CLOSING_BRACE); appendable.append(SINGLE_LINE_BREAK); appendable.append(DOUBLE_TAB); appendable.append(OPENING_CURLY_BRACE); appendable.append(SINGLE_LINE_BREAK); appendable.append(DOUBLE_TAB); appendable.append(TAB); appendable.append(RETURN); appendable.append(SPACE); appendable.append(DOTNET_TRANSLATION_SCOPE); appendable.append(DOT); appendable.append(FGET); appendable.append(OPENING_BRACE); appendable.append(QUOTE); appendable.append(SemanticsNames.REPOSITORY_METADATA_TYPE_SCOPE); appendable.append(QUOTE); appendTranslatedClassList(tScope, appendable); appendable.append(CLOSING_BRACE); appendable.append(END_LINE); appendable.append(SINGLE_LINE_BREAK); appendable.append(DOUBLE_TAB); appendable.append(CLOSING_CURLY_BRACE); appendable.append(SINGLE_LINE_BREAK); } else { appendable.append("\n"); appendable.append("\t\tpublic static SimplTypesScope Get()\n"); appendable.append("\t\t{\n"); appendable.append("\t\t\treturn SimplTypesScope.Get(\"").append(SemanticsNames.REPOSITORY_BUILTIN_DECLARATIONS_TYPE_SCOPE).append("\""); super.appendTranslatedClassList(tScope, appendable); appendable.append(");\n"); appendable.append("\t\t}\n\n"); } } @Override protected void appendTranslatedClassList(SimplTypesScope tScope, Appendable appendable) throws IOException { appendable.append(", MetadataBuiltinsTypesScope.Get()"); super.appendTranslatedClassList(tScope, appendable); // CompilerConfig config = (CompilerConfig) this.config; // MetaMetadataRepository repository = config.loadRepository(); // Collection<MetaMetadata> mmds = repository.values(); // if (mmds != null && mmds.size() > 0) // { // int i = 0; // for (MetaMetadata mmd : mmds) // { // if (mmd.isNewMetadataClass()) // { // ClassDescriptor cd = mmd.getMetadataClassDescriptor(); // if (i > 0) // appendable.append(",\n"); // appendable.append("\t\t\t\ttypeof(" + cd.getDescribedClassSimpleName() + ")"); // } // ++i; // } // } // appendable.append("\n\t\t\t"); } @Override public void addCurrentClassDependency(ClassDescriptor dependency) { addCurrentClassDependency(javaPackage2CSharpNamespace(dependency.getCSharpNamespace())); } }