package ecologylab.bigsemantics.compiler; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.common.collect.Sets.SetView; import ecologylab.bigsemantics.metadata.MetadataClassDescriptor; import ecologylab.bigsemantics.metadata.MetadataFieldDescriptor; import ecologylab.bigsemantics.metadata.builtins.MetadataBuiltinsTypesScope; 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.MetaMetadataScalarField; import ecologylab.bigsemantics.metametadata.MmdCompilerService; import ecologylab.bigsemantics.metametadata.MmdGenericTypeVar; import ecologylab.bigsemantics.metametadata.declarations.MetaMetadataFieldDeclaration; import ecologylab.bigsemantics.metametadata.exceptions.MetaMetadataException; import ecologylab.bigsemantics.namesandnums.SemanticsNames; import ecologylab.generic.Debug; import ecologylab.generic.StringTools; import ecologylab.serialization.ClassDescriptor; import ecologylab.serialization.FieldDescriptor; import ecologylab.serialization.FieldType; import ecologylab.serialization.FieldTypes; import ecologylab.serialization.MetaInformation; import ecologylab.serialization.annotations.simpl_descriptor_classes; import ecologylab.serialization.annotations.simpl_inherit; import ecologylab.serialization.types.ScalarType; import ecologylab.translators.java.JavaTranslationException; import ecologylab.translators.java.JavaTranslator; public class MetaMetadataJavaTranslator extends JavaTranslator implements MmdCompilerService { public static final String SCALAR_GETTER_SETTER_SUFFIX = "Metadata"; private static String[] metaMetadataDefaultDependencies = { MetaMetadataCompositeField.class.getName(), SemanticsNames.class.getName(), MetadataBuiltinsTypesScope.class.getName(), }; public MetaMetadataJavaTranslator() { super(); } @Override protected void initGlobalDependencies() { super.initGlobalDependencies(); for (String dependency : metaMetadataDefaultDependencies) this.addGlobalDependency(dependency); } @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_descriptor_classes.class.getName()); this.addCurrentClassDependency(simpl_inherit.class.getName()); this.addCurrentClassDependency(MetadataClassDescriptor.class.getName()); this.addCurrentClassDependency(MetadataFieldDescriptor.class.getName()); } super.appendClassMetaInformationHook(classDesc, appendable); } @Override protected void appendClassGenericTypeVariables(Appendable appendable, ClassDescriptor inputClass) throws IOException { MetadataClassDescriptor mdInputClass = (MetadataClassDescriptor) inputClass; MetaMetadata mmd = mdInputClass.getDefiningMmd(); MetaMetadataRepository repository = mmd.getRepository(); appendGenericTypeVarDefinitions(appendable, mmd.getGenericTypeVarsList(), repository); } @Override protected void appendSuperClassGenericTypeVariables(Appendable appendable, ClassDescriptor inputClass) throws IOException { MetadataClassDescriptor mdInputClass = (MetadataClassDescriptor) inputClass; MetaMetadata mmd = mdInputClass.getDefiningMmd(); Map<String, MmdGenericTypeVar> gtvs = mmd.getGenericTypeVars(); MetaMetadata superMmd = mmd.getSuperMmd(); Map<String, MmdGenericTypeVar> superGtvs = superMmd.getGenericTypeVars(); List<MmdGenericTypeVar> involvedGtvs = new ArrayList<MmdGenericTypeVar>(); if (gtvs != null && superGtvs != null) { SetView<String> gtvNames = Sets.intersection(gtvs.keySet(), superGtvs.keySet()); for (String gtvName : gtvNames) { involvedGtvs.add(gtvs.get(gtvName)); } MetaMetadataRepository repository = mmd.getRepository(); appendGenericTypeVarParameterizations(appendable, involvedGtvs, repository); } } @Override protected void appendField(ClassDescriptor contextCd, FieldDescriptor fieldDescriptor, Appendable appendable) throws IOException, JavaTranslationException { ((MetadataFieldDescriptor) fieldDescriptor).setCompilerService(this); super.appendField(contextCd, 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, 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) .append(" extends ") .append(MmdGenericTypeVar.getMdClassNameFromMmdOrNoChange(extendsName, repository, this)); appendGenericTypeVarParameterizations(appendable, mmdGenericTypeVar.getNestedGenericTypeVars(), repository); } } if (!first) appendable.append(">"); } } @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 && extendsName == null) { if (first) { appendable.append("<"); first = false; } else { appendable.append(", "); } appendable.append(MmdGenericTypeVar.getMdClassNameFromMmdOrNoChange(argName, repository, this)); appendGenericTypeVarParameterizations(appendable, mmdGenericTypeVar.getNestedGenericTypeVars(), repository); } else if (argName == null && extendsName != null && mmdGenericTypeVar.isRebound()) { if (first) { appendable.append("<"); first = false; } else { appendable.append(", "); } appendable.append(varName); } } 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; MetaMetadataField f = fd.getDefiningMmdField(); if (f != null) f.addAdditionalMetaInformation(fieldDesc.getMetaInformation(), this); else warning("MetaMetadataField not found for " + fd); } @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("\tpublic ").append(classSimpleName) .append("(MetaMetadataCompositeField mmd) {\n"); appendable.append("\t\tsuper(mmd);\n"); appendable.append("\t}\n"); appendable.append("\n"); } protected void appendLazyEvaluation(String fieldName, String typeName, Appendable appendable) throws IOException { appendable.append("\n"); // TODO write comments? // first line. Start of method name appendable.append("\tpublic ").append(typeName).append("\t").append(fieldName) .append("()\n\t{\n"); // second line. Declaration of result variable. appendable.append("\t\t").append(typeName).append("\t").append("result = this.") .append(fieldName).append(";\n"); // third line. Start of if statement appendable.append("\t\tif (result == null)\n\t\t{\n"); // fourth line. creation of new result object. appendable.append("\t\t\tresult = new ").append(typeName).append("();\n"); // fifth line. end of if statement appendable.append("\t\t\tthis.").append(fieldName).append(" = result;\n\t\t}\n"); // sixth line. return statement and end of method. appendable.append("\t\treturn result;\n\t}\n"); } @Override protected void appendGetters(FieldDescriptor fieldDescriptor, Appendable appendable, String suffix) throws IOException { if (fieldDescriptor.getType() == FieldType.SCALAR) { appendValueGetter(fieldDescriptor, appendable); super.appendGetters(fieldDescriptor, appendable, SCALAR_GETTER_SETTER_SUFFIX); } else { super.appendGetters(fieldDescriptor, appendable, suffix); } } private void appendValueGetter(FieldDescriptor fieldDescriptor, Appendable appendable) throws IOException { MetaMetadataScalarField scalar = (MetaMetadataScalarField) ((MetadataFieldDescriptor) fieldDescriptor) .getDefiningMmdField(); // metadata scalar types! ScalarType<?> scalarType = fieldDescriptor.getScalarType(); if (scalarType == null) throw new MetaMetadataException("scalar type not specified!"); String fieldName = fieldDescriptor.getName(); String capFieldName = Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1); String typeName = scalarType.getSimpleName(); appendLazyEvaluation(fieldName, typeName, appendable); ScalarType operativeScalarType = scalarType.operativeScalarType(); String javaPrimitiveTypeName = operativeScalarType.getSimpleName(); appendable.append("\n"); appendable.append("\tpublic ").append(javaPrimitiveTypeName).append(" get") .append(capFieldName).append("()\n"); appendable.append("\t{\n"); appendable.append("\t\treturn this.").append(fieldName).append(" == null ? ") .append(operativeScalarType.defaultValueString()).append(" : ").append(fieldName) .append("().getValue();\n"); appendable.append("\t}\n"); } @Override protected void appendSetters(FieldDescriptor fieldDescriptor, Appendable appendable, String suffix) throws IOException { if (fieldDescriptor.getType() == FieldType.SCALAR) { appendValueSetter(fieldDescriptor, appendable); super.appendSetters(fieldDescriptor, appendable, SCALAR_GETTER_SETTER_SUFFIX); } else { super.appendSetters(fieldDescriptor, appendable, suffix); } } private void appendValueSetter(FieldDescriptor fieldDescriptor, Appendable appendable) throws IOException { // metadata scalar types! ScalarType<?> scalarType = fieldDescriptor.getScalarType(); if (scalarType == null) throw new MetaMetadataException("scalar type not specified!"); String fieldName = fieldDescriptor.getName(); String capFieldName = Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1); ScalarType operativeScalarType = scalarType.operativeScalarType(); String javaPrimitiveTypeName = operativeScalarType.getSimpleName(); appendable.append("\n"); appendable.append("\tpublic void set").append(capFieldName).append("(") .append(javaPrimitiveTypeName).append(" ").append(fieldName).append(")\n"); appendable.append("\t{\n"); appendable.append("\t\tif (").append(fieldName).append(" != ") .append(operativeScalarType.defaultValueString()).append(")\n"); appendable.append("\t\t\tthis.").append(fieldName).append("().setValue(").append(fieldName) .append(");\n"); appendable.append("\t}\n"); } // @Override // protected void appendTranslatedClassList(SimplTypesScope tScope, Appendable appendable) // throws IOException // { // List<String> classes = new ArrayList<String>(); // MetaMetadataRepository repository = ((CompilerConfig) config).loadRepository(); // if (repository.values() != null) // for (MetaMetadata mmd : repository.values()) // if (mmd.isNewMetadataClass() && !mmd.isBuiltIn()) // { // ClassDescriptor cd = mmd.getMetadataClassDescriptor(); // classes.add("\t\t" + cd.getDescribedClassName() + ".class,\n\n"); // } // Collections.sort(classes); // for (String classDef : classes) // appendable.append(classDef); // } @Override protected void generateLibraryTScopeGetter(Appendable appendable, String tScopeName) throws IOException { appendable.append("\tpublic static ").append(JAVA_TRANSLATION_SCOPE).append(" get()\n\t{\n"); appendable.append("\t\treturn ").append(JAVA_TRANSLATION_SCOPE).append(".get("); CompilerConfig cconfig = (CompilerConfig) config; if (cconfig.getBuiltinDeclarationScopeName() == null) { appendable .append("SemanticsNames.REPOSITORY_METADATA_TYPE_SCOPE, MetadataBuiltinsTypesScope.get()"); } else { appendable.append('"').append(cconfig.getBuiltinDeclarationScopeName()).append('"'); } appendable.append(", TRANSLATIONS);\n"); appendable.append("\t}\n\n"); } @Override public void addCurrentClassDependency(ClassDescriptor dependency) { addCurrentClassDependency(dependency.getDescribedClassName()); } @Override public void appendGenericTypeVarExtends(Appendable appendable, Collection<MmdGenericTypeVar> mmdGenericTypeVars, MetaMetadataRepository repository) throws IOException { // TODO Auto-generated method stub } }