/* * ****************************************************************************** * MontiCore Language Workbench * Copyright (c) 2015, MontiCore, All rights reserved. * * This project is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this project. If not, see <http://www.gnu.org/licenses/>. * ****************************************************************************** */ package de.monticore.codegen; import static de.monticore.codegen.mc2cd.TransformationHelper.createSimpleReference; import static de.monticore.codegen.mc2cd.transl.ConstantsTranslation.CONSTANTS_ENUM; import static de.monticore.grammar.Multiplicity.multiplicityByAlternative; import static de.monticore.grammar.Multiplicity.multiplicityByIteration; import static java.util.Collections.max; import java.io.File; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; import com.google.common.base.Joiner; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import de.monticore.ast.ASTNode; import de.monticore.codegen.cd2java.ast.AstGeneratorHelper; import de.monticore.codegen.cd2java.ast_emf.AstEmfGeneratorHelper; import de.monticore.codegen.mc2cd.MC2CDStereotypes; import de.monticore.codegen.mc2cd.MCGrammarSymbolTableHelper; import de.monticore.codegen.mc2cd.TransformationHelper; import de.monticore.grammar.Multiplicity; import de.monticore.grammar.grammar._ast.ASTClassProd; import de.monticore.grammar.grammar._ast.ASTInterfaceProd; import de.monticore.grammar.grammar._ast.ASTMCGrammar; import de.monticore.grammar.grammar._ast.ASTNonTerminal; import de.monticore.grammar.grammar._ast.ASTProd; import de.monticore.grammar.grammar._ast.ASTRuleReference; import de.monticore.grammar.symboltable.MCProdSymbol; import de.monticore.io.FileReaderWriter; import de.monticore.io.paths.IterablePath; import de.monticore.java.prettyprint.JavaDSLPrettyPrinter; import de.monticore.prettyprint.IndentPrinter; import de.monticore.symboltable.CommonSymbol; import de.monticore.symboltable.GlobalScope; import de.monticore.symboltable.types.references.ActualTypeArgument; import de.monticore.types.TypesHelper; import de.monticore.types.TypesPrinter; import de.monticore.types.types._ast.ASTImportStatement; import de.monticore.types.types._ast.ASTSimpleReferenceType; import de.monticore.types.types._ast.ASTType; import de.monticore.umlcd4a.CD4AnalysisHelper; import de.monticore.umlcd4a.cd4analysis._ast.ASTCD4AnalysisNode; import de.monticore.umlcd4a.cd4analysis._ast.ASTCDAttribute; import de.monticore.umlcd4a.cd4analysis._ast.ASTCDClass; import de.monticore.umlcd4a.cd4analysis._ast.ASTCDCompilationUnit; import de.monticore.umlcd4a.cd4analysis._ast.ASTCDDefinition; import de.monticore.umlcd4a.cd4analysis._ast.ASTCDEnum; import de.monticore.umlcd4a.cd4analysis._ast.ASTCDEnumConstant; import de.monticore.umlcd4a.cd4analysis._ast.ASTCDInterface; import de.monticore.umlcd4a.cd4analysis._ast.ASTCDMethod; import de.monticore.umlcd4a.cd4analysis._ast.ASTCDType; import de.monticore.umlcd4a.cd4analysis._ast.ASTStereotype; import de.monticore.umlcd4a.prettyprint.CDPrettyPrinterConcreteVisitor; import de.monticore.umlcd4a.symboltable.CDFieldSymbol; import de.monticore.umlcd4a.symboltable.CDSymbol; import de.monticore.umlcd4a.symboltable.CDTypeSymbol; import de.monticore.umlcd4a.symboltable.CDTypes; import de.monticore.umlcd4a.symboltable.Stereotype; import de.monticore.umlcd4a.symboltable.references.CDTypeSymbolReference; import de.monticore.utils.ASTNodes; import de.se_rwth.commons.JavaNamesHelper; import de.se_rwth.commons.Names; import de.se_rwth.commons.StringTransformations; import de.se_rwth.commons.logging.Log; /** * TODO: Write me! * * @author (last commit) $Author$ * @version $Revision$, $Date$ */ public class GeneratorHelper extends TypesHelper { public static final String AST_PREFIX = "AST"; public static final String AST_NODE = "ASTNode"; public static final String AST_NODE_CLASS_NAME = "de.monticore.ast.ASTNode"; public static final String ASTC_NODE_CLASS_NAME = "mc.ast.ASTCNode"; public static final String AST_PACKAGE_SUFFIX = "_ast"; public static final String VISITOR_PACKAGE_SUFFIX = "_visitor"; public static final String TYPERESOLVER_PACKAGE_SUFFIX = "_types"; public static final String COCOS_PACKAGE_SUFFIX = "_cocos"; public static final String PARSER_PACKAGE_SUFFIX = "._parser"; public static final String AST_DOT_PACKAGE_SUFFIX = "._ast"; public static final String AST_PACKAGE_SUFFIX_DOT = "_ast."; public static final String AST_DOT_PACKAGE_SUFFIX_DOT = "._ast."; public static final String MC_CONCRETE_PARSER_CONTEXT = "MCParser"; public static final String BUILDER_PREFIX = "Builder_"; public static final String OPTIONAL = "Optional"; public static final String SYMBOL = "Symbol"; public static final String SCOPE = "Scope"; public static final String BASE = "Node"; public static final String CD_EXTENSION = ".cd"; public static final String GET_PREFIX_BOOLEAN = "is"; public static final String GET_PREFIX_NOT_BOOLEAN = "get"; public static final String SET_PREFIX = "set"; public static final String ARRAY_LIST = "ArrayList"; public static final String JAVA_LIST = "java.util.List"; public static final int STAR = -1; protected static final String LOG_NAME = "GeneratorHelper"; // TODO: reserve names of the base grammars like CD4A, Types, Common ... private static List<String> reservedCdNames = Arrays.asList(new String[] { // CD4A "derived", "association", "composition", // Common.mc4 "local", "readonly"}); static JavaDSLPrettyPrinter javaPrettyPrinter; static CDPrettyPrinterConcreteVisitor cdPrettyPrinter; protected static Collection<String> additionalAttributes = Lists.newArrayList(SYMBOL, SCOPE); protected ASTCDDefinition cdDefinition; protected String packageName; protected String qualifiedName; // preserves order of appearance in the extends list of the grammar protected List<String> superGrammarCds = new ArrayList<>(); protected GlobalScope symbolTable; protected CDSymbol cdSymbol; public GeneratorHelper(ASTCDCompilationUnit topAst, GlobalScope symbolTable) { Preconditions.checkArgument(topAst.getCDDefinition() != null); cdDefinition = topAst.getCDDefinition(); this.symbolTable = symbolTable; // Qualified Name qualifiedName = Names.getQualifiedName(topAst.getPackage(), getCdName()); // CD package packageName = getCdPackage(qualifiedName); // CD symbol this.cdSymbol = getCd(); // Create list of CDs for super grammars for (ASTImportStatement importSt : topAst.getImportStatements()) { if (importSt.isStar()) { superGrammarCds.add(Names.getQualifiedName(importSt.getImportList())); } } } /** * Converts CD type to Java type using the given package suffix. * * @param type * @param packageSuffix * @return converted type or original type if type is java type already */ public void transformTypeCd2Java(ASTSimpleReferenceType astType, String packageSuffix) { Log.trace("Converted Cd or Java type: " + TypesPrinter.printType(astType), LOG_NAME); String genericType = ""; ASTSimpleReferenceType convertedType = astType; if (isOptional(astType)) { Optional<ASTSimpleReferenceType> typeArgument = TypesHelper .getFirstTypeArgumentOfOptional(astType); if (!typeArgument.isPresent()) { return; } convertedType = typeArgument.get(); genericType = OPTIONAL; } else if (TypesHelper.isGenericTypeWithOneTypeArgument(astType, ARRAY_LIST)) { Optional<ASTSimpleReferenceType> typeArgument = TypesHelper .getFirstTypeArgumentOfGenericType(astType, ARRAY_LIST); if (!typeArgument.isPresent()) { return; } convertedType = typeArgument.get(); genericType = ARRAY_LIST; } else if (TypesHelper.isGenericTypeWithOneTypeArgument(astType, JAVA_LIST)) { Optional<ASTSimpleReferenceType> typeArgument = TypesHelper .getFirstTypeArgumentOfGenericType(astType, JAVA_LIST); if (!typeArgument.isPresent()) { return; } convertedType = typeArgument.get(); genericType = JAVA_LIST; } String convertedTypeName = TypesPrinter.printType(convertedType); // Resolve only qualified types if (!convertedTypeName.contains(".")) { return; } // TODO: GV, PN: path converter by resolving if (convertedTypeName.contains("<")) { return; } Optional<CDTypeSymbol> symbol = resolveCdType(convertedTypeName); if (symbol.isPresent()) { CDTypeSymbol cdType = symbol.get(); Log.trace("CD Type: " + cdType, LOG_NAME); String typeName = cdType.getModelName().toLowerCase() + packageSuffix + cdType.getName(); if (!genericType.isEmpty()) { convertedType.setNames(Arrays.asList(typeName.split("\\."))); return; } astType.setNames(Arrays.asList(typeName.split("\\."))); } else { Log.debug("CD or Java type couldn't be resolved: " + convertedTypeName, LOG_NAME); } return; } /** * Converts CD type to Java type using the given package suffix. * * @param type * @param packageSuffix * @return converted type or original type if type is java type already */ public ASTSimpleReferenceType convertTypeCd2Java(ASTSimpleReferenceType astType, String packageSuffix) { Log.trace("Converted Cd or Java type: " + TypesPrinter.printType(astType), LOG_NAME); String genericType = ""; ASTSimpleReferenceType convertedType = astType; if (isOptional(astType)) { Optional<ASTSimpleReferenceType> typeArgument = TypesHelper .getFirstTypeArgumentOfOptional(astType); if (!typeArgument.isPresent()) { return astType; } convertedType = typeArgument.get(); genericType = OPTIONAL; } else if (TypesHelper.isGenericTypeWithOneTypeArgument(astType, ARRAY_LIST)) { Optional<ASTSimpleReferenceType> typeArgument = TypesHelper .getFirstTypeArgumentOfGenericType(astType, ARRAY_LIST); if (!typeArgument.isPresent()) { return astType; } convertedType = typeArgument.get(); genericType = ARRAY_LIST; } else if (TypesHelper.isGenericTypeWithOneTypeArgument(astType, JAVA_LIST)) { Optional<ASTSimpleReferenceType> typeArgument = TypesHelper .getFirstTypeArgumentOfGenericType(astType, JAVA_LIST); if (!typeArgument.isPresent()) { return astType; } convertedType = typeArgument.get(); genericType = JAVA_LIST; } String convertedTypeName = TypesPrinter.printType(convertedType); // Resolve only qualified types if (!convertedTypeName.contains(".")) { return astType; } // TODO: GV, PN: path converter by resolving if (convertedTypeName.contains("<")) { return astType; } Optional<CDTypeSymbol> symbol = resolveCdType(convertedTypeName); if (symbol.isPresent()) { CDTypeSymbol cdType = symbol.get(); Log.trace("CD Type: " + cdType, LOG_NAME); String typeName = cdType.getModelName().toLowerCase() + packageSuffix + cdType.getName(); if (!genericType.isEmpty()) { return createSimpleReference(genericType, typeName); } return createSimpleReference(typeName); } else { Log.debug("CD or Java type couldn't be resolved: " + convertedTypeName, LOG_NAME); } return astType; } /** * Converts CD type to Java type using the given package suffix. * * @param type * @param packageSuffix * @return converted type or original type if type is java type already */ public String convertTypeCd2Java(CDTypeSymbolReference astType, String packageSuffix) { Log.trace("Converted Cd or Java type: " + astType.getName(), LOG_NAME); String genericType = ""; CDTypeSymbolReference convertedType = astType; if (isOptional(astType)) { List<ActualTypeArgument> typeArgs = astType.getActualTypeArguments(); if (typeArgs.size() != 1) { return astType.getName(); } CDTypeSymbolReference typeArgument = (CDTypeSymbolReference) typeArgs.get(0).getType(); convertedType = typeArgument; genericType = OPTIONAL; } else if (isList(astType)) { List<ActualTypeArgument> typeArgs = astType.getActualTypeArguments(); if (typeArgs.size() != 1) { return astType.getName(); } CDTypeSymbolReference typeArgument = (CDTypeSymbolReference) typeArgs.get(0).getType(); convertedType = typeArgument; genericType = JAVA_LIST; } String convertedTypeName = convertedType.isReferencedSymbolLoaded() ? convertedType.getFullName() : convertedType.getName(); // Resolve only qualified types if (!convertedTypeName.contains(".")) { return astType.getName(); } // TODO: GV, PN: path converter by resolving if (convertedTypeName.contains("<")) { return astType.getName(); } Optional<CDTypeSymbol> symbol = resolveCdType(convertedTypeName); if (symbol.isPresent()) { CDTypeSymbol cdType = symbol.get(); Log.trace("CD Type: " + cdType, LOG_NAME); String typeName = cdType.getModelName().toLowerCase() + packageSuffix + cdType.getName(); if (!genericType.isEmpty()) { return getGenericTypeName(genericType, typeName); } return typeName; } else { Log.debug("CD or Java type couldn't be resolved: " + convertedTypeName, LOG_NAME); } return astType.getName(); } /** * TODO: Write me! * * @param genericType * @param typeName * @return */ public String getGenericTypeName(String genericType, String typeName) { return genericType + '<' + typeName + '>'; } /** * @return cdSymbol */ public CDSymbol getCdSymbol() { return this.cdSymbol; } /** * @return name of the language's AST-Nodes marker interface * @see #getASTNodeBaseType(String) */ public String getASTNodeBaseType() { return getASTNodeBaseType(getCdName()); } /** * @return name of the language's and (recursive) super languages' AST-Nodes * marker interface * @see #getASTNodeBaseType() */ public Collection<String> getASTNodeBaseTypes() { Set<String> baseNodesNames = new LinkedHashSet<>(); for (CDSymbol cd : getAllCds(getCd())) { String qualifiedCdName = cd.getFullName(); String simpleCdName = getCdName(qualifiedCdName); String baseNodeName = getASTNodeBaseType(simpleCdName); String astPackage = AstGeneratorHelper.getAstPackage(qualifiedCdName); baseNodesNames.add(Names.getQualifiedName(astPackage, baseNodeName)); } return baseNodesNames; } // -------------- Static methods ------------ /** * @return full qualified name of the overall interface for AST nodes * @see #getASTNodeType() */ public static String getQualifiedASTNodeType() { return AST_NODE_CLASS_NAME; } /** * @return name of the overall interface for AST nodes * @see #getQualifiedASTNodeType() */ public static String getASTNodeType() { return AST_NODE; } /** * @return name of the language's AST-Nodes marker interface * @see #getASTNodeBaseType() */ public static String getASTNodeBaseType(String languageName) { return AST_PREFIX + languageName + BASE; } public String getTypeResolverPackage() { return getTypeResolverPackage(getPackageName()); } public static String getTypeResolverPackage(String qualifiedLanguageName) { return getPackageName(qualifiedLanguageName.toLowerCase(), getTypeResolverPackageSuffix()); } public static String getTypeResolverPackageSuffix() { return GeneratorHelper.TYPERESOLVER_PACKAGE_SUFFIX; } public String getVisitorPackage() { return getVisitorPackage(getPackageName()); } public static String getVisitorPackage(String qualifiedLanguageName) { return getPackageName(qualifiedLanguageName.toLowerCase(), getVisitorPackageSuffix()); } public static String getVisitorPackageSuffix() { return GeneratorHelper.VISITOR_PACKAGE_SUFFIX; } public static boolean isAdditionalAttribute(ASTCDAttribute attrib) { return isOptional(attrib.getType()) && additionalAttributes.stream().filter( a -> a.equals(getReferenceNameFromOptional(attrib.getType()))).findAny() .isPresent(); } public static List<ASTCDAttribute> getNativeCDAttributes(ASTCDClass clazz) { return clazz.getCDAttributes().stream().filter(attr -> !isAdditionalAttribute(attr)) .collect(Collectors.toList()); } public boolean hasOnlyAstAttributes(ASTCDClass type) { for (ASTCDAttribute attr : type.getCDAttributes()) { if (!isAstNode(attr)) { return false; } } return true; } public static boolean isString(String type) { return "String".equals(type) || "java.lang.String".equals(type); } public static boolean isString(ASTSimpleReferenceType type) { String typeName = getSimpleName(type.getNames()); return "String".equals(typeName) || "java.lang.String".equals(typeName); } public static String getSimpleName(List<String> nameAsList) { if (nameAsList == null || nameAsList.isEmpty()) { return ""; } return nameAsList.get(nameAsList.size() - 1); } public String getAstClassNameForASTLists(CDFieldSymbol field) { // TODO for default types (e.g. String) this field.getType() would try to // resolve the default type but fail // hence we currently use the ast methods instead of // "return isOptionalAstNode(field.getType())" return getAstClassNameForASTLists(field.getType()); } public String getAstClassNameForASTLists(CDTypeSymbolReference field) { List<ActualTypeArgument> typeArgs = field.getActualTypeArguments(); if (typeArgs.size() != 1) { return AST_NODE_CLASS_NAME; } if (!(typeArgs.get(0).getType() instanceof CDTypeSymbolReference)) { return AST_NODE_CLASS_NAME; } String arg = typeArgs.get(0).getType().getReferencedSymbol().getFullName(); return AstGeneratorHelper.getAstPackage(Names.getQualifier(arg)) + Names.getSimpleName(arg); } public String getAstClassNameForASTLists(ASTCDAttribute attr) { if (!attr.getSymbol().isPresent()) { return ""; } if (!(attr.getSymbol().get() instanceof CDFieldSymbol)) { Log.error(String.format("0xA04125 Symbol of ASTCDAttribute %s is not CDFieldSymbol.", attr.getName())); } return getAstClassNameForASTLists(((CDFieldSymbol) attr.getSymbol().get()).getType()); } public static boolean isOptional(ASTCDAttribute attribute) { return isOptional(attribute.getType()); } public static boolean isOptional(CDTypeSymbol type) { // TODO proper implementation if (OPTIONAL.equals(type.getName())) { return true; } if (!type.getAstNode().isPresent()) { Log.debug(String.format("ASTNode of cd type symbol %s is not set.", type.getName()), LOG_NAME); return false; } ASTNode node = type.getAstNode().get(); if (!(node instanceof ASTType)) { Log.error(String .format( "0xA5009 Expected the ASTNode of cd type symbol %s to be an ASTType, but it is of kind %s", type.getFullName(), node.getClass().getName())); return false; } return isOptional((ASTType) node); } public static boolean isOptional(CDFieldSymbol field) { return isOptional(field.getType()); } public boolean isAstNode(CDTypeSymbol type) { String typeName = type.getName(); if (!typeName.contains(".") && !typeName.startsWith(AST_PREFIX)) { return false; } else { List<String> listName = TypesHelper.createListFromDotSeparatedString(typeName); if (!listName.get(listName.size() - 1).startsWith(AST_PREFIX)) { return false; } } if (!(type instanceof CDTypeSymbolReference)) { return type.isClass() || type.isInterface(); } CDTypeSymbolReference attrType = (CDTypeSymbolReference) type; if (!attrType.getActualTypeArguments().isEmpty()) { return false; } return attrType.existsReferencedSymbol() && !attrType.isEnum(); } public boolean isOptionalAstNode(CDFieldSymbol field) { // TODO for default types (e.g. String) this field.getType() would try to // resolve the default type but fail // hence we currently use the ast methods instead of // "return isOptionalAstNode(field.getType())" return isOptionalAstNode(field.getType()); } public boolean isListAstNode(CDFieldSymbol field) { // TODO for default types (e.g. String) this field.getType() would try to // resolve the default type but fail // hence we currently use the ast methods instead of // "return isOptionalAstNode(field.getType())" return isListAstNode(field.getType()); } public boolean isAstNode(CDFieldSymbol field) { // TODO for default types (e.g. String) this field.getType() would try to // resolve the default type but fail // hence we currently use the ast methods instead of // "return isAstNode(field.getType())" return isAstNode(field.getType()); } public static boolean isListType(String type) { // TODO : use symbol table int index = type.indexOf('<'); if (index != -1) { type = type.substring(0, index); } return "List".equals(type) || "java.util.List".equals(type) || "ArrayList".equals(type) || "java.util.ArrayList".equals(type); } public static boolean isMapType(String type) { // TODO : use symbol table int index = type.indexOf('<'); if (index != -1) { type = type.substring(0, index); } return "Map".equals(type) || "java.util.Map".equals(type) || "HashMap".equals(type) || "java.util.HashMap".equals(type); } public static boolean isAbstract(ASTCDClass clazz) { return clazz.getModifier().isPresent() && clazz.getModifier().get().isAbstract(); } public static boolean isAbstract(ASTCDMethod method, ASTCDInterface type) { return true; } public static boolean isAbstract(ASTCDMethod method, ASTCDEnum type) { return false; } public static boolean isAbstract(ASTCDMethod method, ASTCDClass type) { return CD4AnalysisHelper.isAbstract(method); } public static boolean isInherited(ASTCDAttribute attribute) { return CD4AnalysisHelper.hasStereotype(attribute, MC2CDStereotypes.INHERITED.toString()); } public boolean isEnum(String qualifiedName) { Optional<CDTypeSymbol> cdType = resolveCdType(qualifiedName); return cdType.isPresent() && cdType.get().isEnum(); } public boolean isAttributeOfTypeEnum(ASTCDAttribute attr) { if (!attr.getSymbol().isPresent() || !(attr.getSymbol().get() instanceof CDFieldSymbol)) { return false; } CDTypeSymbolReference attrType = ((CDFieldSymbol) attr.getSymbol() .get()).getType(); List<ActualTypeArgument> typeArgs = attrType.getActualTypeArguments(); if (typeArgs.size() > 1) { return false; } String typeName = typeArgs.isEmpty() ? attrType.getName() : typeArgs.get(0).getType().getName(); if (!typeName.contains(".") && !typeName.startsWith(AST_PREFIX)) { return false; } List<String> listName = TypesHelper.createListFromDotSeparatedString(typeName); if (!listName.get(listName.size() - 1).startsWith(AST_PREFIX)) { return false; } if (typeArgs.isEmpty()) { return attrType.existsReferencedSymbol() && attrType.isEnum(); } CDTypeSymbolReference typeArgument = (CDTypeSymbolReference) typeArgs .get(0).getType(); return typeArgument.existsReferencedSymbol() && typeArgument.isEnum(); } /** * TODO: Write me! * * @param cdAttribute * @param type * @return */ public boolean isAttributeOfSuperType(ASTCDAttribute cdAttribute, ASTCDType type) { if (!type.getSymbol().isPresent()) { Log.error("0xA5010 Could not load symbol information for " + type.getName() + "."); return false; } CDTypeSymbol sym = (CDTypeSymbol) type.getSymbol().get(); return getAllVisibleFieldsOfSuperTypes(sym).stream().map(a -> a.getName()) .collect(Collectors.toList()).contains(cdAttribute.getName()); } /** * TODO: Write me! * * @param field * @param type * @return */ public boolean isAttributeOfSuperType(CDFieldSymbol field, CDTypeSymbol type) { return getAllVisibleFieldsOfSuperTypes(type).stream().map(a -> a.getName()) .collect(Collectors.toList()).contains(field.getName()); } /** * TODO: Write me! * * @param cdType * @return */ public Collection<CDFieldSymbol> getAllVisibleFieldsOfSuperTypes(CDTypeSymbol cdType) { final Set<CDFieldSymbol> allSuperTypeFields = new LinkedHashSet<>(); for (CDTypeSymbol superType : cdType.getSuperTypes()) { for (CDFieldSymbol superField : superType.getFields()) { allSuperTypeFields.add(superField); } allSuperTypeFields.addAll(getAllVisibleFieldsOfSuperTypes(superType)); } // filter-out all private fields final Set<CDFieldSymbol> allVisibleSuperTypeFields = allSuperTypeFields.stream() .filter(field -> !field.isPrivate()) .collect(Collectors.toCollection(LinkedHashSet::new)); return ImmutableSet.copyOf(allVisibleSuperTypeFields); } /** * TODO: Write me! * * @param type * @return */ public Optional<String> getTypeNameToResolve(ASTSimpleReferenceType astType) { ASTSimpleReferenceType convertedType = astType; if (isOptional(astType)) { Optional<ASTSimpleReferenceType> typeArgument = TypesHelper .getFirstTypeArgumentOfOptional(astType); if (!typeArgument.isPresent()) { return Optional.empty(); } convertedType = typeArgument.get(); } else if (TypesHelper.isGenericTypeWithOneTypeArgument(astType, ARRAY_LIST)) { Optional<ASTSimpleReferenceType> typeArgument = TypesHelper .getFirstTypeArgumentOfGenericType(astType, ARRAY_LIST); if (!typeArgument.isPresent()) { return Optional.empty(); } convertedType = typeArgument.get(); } else if (TypesHelper.isGenericTypeWithOneTypeArgument(astType, JAVA_LIST)) { Optional<ASTSimpleReferenceType> typeArgument = TypesHelper .getFirstTypeArgumentOfGenericType(astType, JAVA_LIST); if (!typeArgument.isPresent()) { return Optional.empty(); } convertedType = typeArgument.get(); } String convertedTypeName = TypesPrinter.printType(convertedType); // Resolve only qualified types if (!convertedTypeName.contains(".")) { return Optional.empty(); } // TODO: GV, PN: path converter by resolving if (convertedTypeName.contains("<")) { return Optional.empty(); } return Optional.of(convertedTypeName); } /** * Gets super types recursively (without duplicates - the first occurrence in * the type hierarchy is used) * * @param type * @return all supertypes (without the type itself) */ // TODO PN<-RH: how to refactor to cd4a symbol table? type.getSuperTypes() is // based on CommonJTypeSymbol public List<CDTypeSymbol> getSuperTypes(CDTypeSymbol type) { List<CDTypeSymbol> allSuperTypes = new ArrayList<>(); for (CDTypeSymbol s : type.getSuperTypes()) { addIfNotContained(s, allSuperTypes); List<CDTypeSymbol> supers = getSuperTypes(s); for (CDTypeSymbol sup : supers) { addIfNotContained(sup, allSuperTypes); } } return allSuperTypes; } /** * Gets super types recursively (without duplicates - the first occurrence in * the type hierarchy is used) * * @param type * @return all supertypes (without the type itself) */ // TODO PN<-RH: how to refactor to cd4a symbol table? type.getSuperTypes() is // based on CommonJTypeSymbol public List<CDTypeSymbol> getAllSuperInterfaces(CDTypeSymbol type) { List<CDTypeSymbol> allSuperTypes = new ArrayList<>(); for (CDTypeSymbol s : type.getSuperTypes()) { if (s.isInterface()) { addIfNotContained(s, allSuperTypes); } List<CDTypeSymbol> supers = getSuperTypes(s); for (CDTypeSymbol sup : supers) { if (sup.isInterface()) { addIfNotContained(sup, allSuperTypes); } } } return allSuperTypes; } protected static <T extends CommonSymbol> void addIfNotContained(T toAdd, List<T> list) { if (!list.stream() .filter(t -> t.getName().equals(toAdd.getName())) .findAny() .isPresent()) { list.add(toAdd); } } /** * Gets the java super types of the given interf (without the interf itself). * * @param interf * @return */ public Collection<String> getSuperTypes(ASTCDInterface interf) { if (!interf.getSymbol().isPresent()) { Log.error("0xA5011 Could not load symbol information for " + interf.getName() + "."); } CDTypeSymbol sym = (CDTypeSymbol) interf.getSymbol().get(); List<CDTypeSymbol> allSuperTypes = getSuperTypes(sym); List<String> theSuperTypes = allSuperTypes.stream().map(t -> t.getFullName()) .collect(Collectors.toList()); // transform to java types theSuperTypes = theSuperTypes.stream() .map(s -> AstGeneratorHelper.getAstPackage(Names.getQualifier(s)) + Names.getSimpleName(s)) .collect(Collectors.toList()); return theSuperTypes; } /** * Gets the java super types of the given clazz (without the clazz itself). * * @param clazz * @return */ public List<String> getSuperTypes(ASTCDClass clazz) { if (!clazz.getSymbol().isPresent()) { Log.error("0xA5007 Could not load symbol information for " + clazz.getName() + "."); } CDTypeSymbol sym = (CDTypeSymbol) clazz.getSymbol().get(); List<CDTypeSymbol> allSuperTypes = getSuperTypes(sym); List<String> theSuperTypes = allSuperTypes.stream().map(t -> t.getFullName()) .collect(Collectors.toList()); // transform to java types theSuperTypes = theSuperTypes.stream() .map(s -> AstGeneratorHelper.getAstPackage(Names.getQualifier(s)) + Names.getSimpleName(s)) .collect(Collectors.toList()); return theSuperTypes; } /** * Gets the java super types of the given clazz (without the clazz itself). * * @param clazz * @return */ public List<CDTypeSymbol> getAllSuperInterfaces(ASTCDType type) { if (!type.getSymbol().isPresent()) { Log.error("0xA5001 Could not load symbol information for " + type.getName() + "."); } CDTypeSymbol sym = (CDTypeSymbol) type.getSymbol().get(); return getAllSuperInterfaces(sym); } public static String getSuperClass(ASTCDClass clazz) { if (!clazz.getSuperclass().isPresent()) { return "de.monticore.ast.ASTCNode"; } return clazz.printSuperClass(); } public static String getSuperClassForBuilder(ASTCDClass clazz) { if (!clazz.getSuperclass().isPresent()) { return ""; } return clazz.printSuperClass(); } public static List<String> getValuesOfConstantEnum(ASTCDDefinition ast) { List<String> astConstants = new ArrayList<>(); ASTCDEnum constants = null; Iterator<ASTCDEnum> it = ast.getCDEnums().iterator(); while (it.hasNext() && constants == null) { ASTCDEnum cdEnum = it.next(); if (cdEnum.getName().equals(ast.getName() + CONSTANTS_ENUM)) { constants = cdEnum; } } if (constants != null) { for (ASTCDEnumConstant constant : constants.getCDEnumConstants()) { astConstants.add(constant.getName()); } } return astConstants; } public static List<CDFieldSymbol> getVisibleFields(CDTypeSymbol cdType) { return cdType.getFields().stream().filter(a -> !a.isPrivate()).collect(Collectors.toList()); } public static JavaDSLPrettyPrinter getJavaPrettyPrinter() { if (javaPrettyPrinter == null) { javaPrettyPrinter = new JavaDSLPrettyPrinter(new IndentPrinter()); } return javaPrettyPrinter; } public static CDPrettyPrinterConcreteVisitor getCDPrettyPrinter() { if (cdPrettyPrinter == null) { cdPrettyPrinter = new CDPrettyPrinterConcreteVisitor(new IndentPrinter()); } return cdPrettyPrinter; } public boolean isListAstNode(ASTCDAttribute attribute) { if (!attribute.getSymbol().isPresent()) { return false; } if (!(attribute.getSymbol().get() instanceof CDFieldSymbol)) { Log.error(String.format("0xA5012 Symbol of ASTCDAttribute %s is not CDFieldSymbol.", attribute.getName())); } return isListAstNode(((CDFieldSymbol) attribute.getSymbol().get()).getType()); } public boolean isListAstNode(CDTypeSymbolReference type) { if (!type.getName().equals(JAVA_LIST)) { return false; } List<ActualTypeArgument> typeArgs = type.getActualTypeArguments(); if (typeArgs.size() != 1) { return false; } if (!(typeArgs.get(0).getType() instanceof CDTypeSymbolReference)) { return false; } return isAstNode((CDTypeSymbolReference) typeArgs.get(0).getType()); } public boolean isList(CDTypeSymbolReference type) { if (!type.getName().equals(JAVA_LIST)) { return false; } return type.getActualTypeArguments().size() == 1; } public boolean isListOfString(CDFieldSymbol field) { CDTypeSymbolReference type = field.getType(); if (!type.getName().equals(JAVA_LIST)) { return false; } List<ActualTypeArgument> typeArgs = type.getActualTypeArguments(); if (typeArgs.size() != 1) { return false; } return isString(typeArgs.get(0).getType().getName()); } public boolean isOptionalAstNode(CDTypeSymbolReference type) { if (!type.getName().equals(OPTIONAL)) { return false; } List<ActualTypeArgument> typeArgs = type.getActualTypeArguments(); if (typeArgs.size() != 1) { return false; } if (!(typeArgs.get(0).getType() instanceof CDTypeSymbolReference)) { return false; } return isAstNode((CDTypeSymbolReference) typeArgs.get(0).getType()); } public static boolean isSupertypeOfHWType(String className) { return className.startsWith(AST_PREFIX) && className.endsWith(TransformationHelper.GENERATED_CLASS_SUFFIX); } public static String getJavaConformName(String name) { return JavaNamesHelper.javaAttribute(name); } public static String getCdLanguageConformName(String name) { if (reservedCdNames.contains(name)) { return (JavaNamesHelper.PREFIX_WHEN_WORD_IS_RESERVED + name).intern(); } return name.intern(); } public static boolean isQualified(String name) { return name.contains("."); } public static String getJavaAndCdConformName(String name) { Log.errorIfNull(name); return getCdLanguageConformName(getJavaConformName(name)); } public boolean isAstNode(ASTCDAttribute attr) { if (!attr.getSymbol().isPresent()) { return false; } if (!(attr.getSymbol().get() instanceof CDFieldSymbol)) { Log.error(String.format("0xA5013 Symbol of ASTCDAttribute %s is not CDFieldSymbol.", attr.getName())); } return isAstNode(((CDFieldSymbol) attr.getSymbol().get()).getType()); } public boolean isOptionalAstNode(ASTCDAttribute attr) { if (!attr.getSymbol().isPresent()) { return false; } if (!(attr.getSymbol().get() instanceof CDFieldSymbol)) { Log.error(String.format("0xA5014 Symbol of ASTCDAttribute %s is not CDFieldSymbol.", attr.getName())); } return isOptionalAstNode(((CDFieldSymbol) attr.getSymbol().get()).getType()); } public String getTypeNameWithoutOptional(ASTCDAttribute attribute) { if (isOptional(attribute)) { return TypesHelper .printType(TypesHelper.getSimpleReferenceTypeFromOptional(attribute.getType())); } return attribute.printType(); } public String getCdTypeNameWithoutOptional(CDFieldSymbol attribute) { CDTypeSymbolReference type = attribute.getType(); if (!isOptional(type)) { return type.getName(); } return type.getActualTypeArguments().get(0).getType().getName(); } public String getJavaTypeNameWithoutOptional(CDFieldSymbol attribute) { CDTypeSymbolReference type = attribute.getType(); if (!isOptional(type)) { return convertTypeCd2Java(type, AST_DOT_PACKAGE_SUFFIX_DOT); } return convertTypeCd2Java( (CDTypeSymbolReference) type.getActualTypeArguments().get(0).getType(), AST_DOT_PACKAGE_SUFFIX_DOT); } public static boolean isBuilderClass(ASTCDClass clazz) { return clazz.getName().startsWith("Builder_"); } public static String getPlainGetter(ASTCDAttribute ast) { StringBuilder getPrefix = CDTypes.isBoolean(printType(ast.getType())) ? new StringBuilder(GET_PREFIX_BOOLEAN) : new StringBuilder(GET_PREFIX_NOT_BOOLEAN); return getPrefix .append(StringTransformations.capitalize(getNativeAttributeName(ast.getName()))).toString(); } public static String getPlainName(ASTCDAttribute ast) { return StringTransformations.capitalize(getNativeAttributeName(ast.getName())); } public static String getPlainGetter(CDFieldSymbol field) { StringBuilder getPrefix = CDTypes.isBoolean(field.getType().getName()) ? new StringBuilder(GET_PREFIX_BOOLEAN) : new StringBuilder(GET_PREFIX_NOT_BOOLEAN); return getPrefix .append(StringTransformations.capitalize(getNativeAttributeName(field.getName()))) .toString(); } /** * Returns the plain getter for the given attribute */ public static String getPlainSetter(ASTCDAttribute ast) { return new StringBuilder(SET_PREFIX).append( StringTransformations.capitalize(getNativeAttributeName(ast.getName()))) .toString(); } /** * Returns the plain getter for the given attribute */ public static String getPlainSetter(CDFieldSymbol field) { return new StringBuilder(SET_PREFIX).append( StringTransformations.capitalize(getNativeAttributeName(field.getName()))) .toString(); } /** * Returns name without suffix for HW classes * * @param type * @return */ public static String getPlainName(ASTCDType type) { String name = type.getName(); if (isSupertypeOfHWType(name)) { return name.substring(0, name.lastIndexOf(TransformationHelper.GENERATED_CLASS_SUFFIX)); } return name; } public static String getPlainName(ASTCDInterface clazz) { String name = clazz.getName(); if (isSupertypeOfHWType(name)) { return name.substring(0, name.lastIndexOf(TransformationHelper.GENERATED_CLASS_SUFFIX)); } return name; } /** * Checks if the node is part of the current language (or one of its super * languages) or if it is external (e.g. String, List, etc.) * * @param type * @return */ public static boolean isExternal(ASTCDType type, String superType) { if (!type.getModifier().isPresent()) { return false; } if (!type.getModifier().get().getStereotype().isPresent()) { return false; } ASTStereotype stereoTypes = type.getModifier().get().getStereotype().get(); return stereoTypes.getValues().stream() .filter(value -> value.getName().equals(MC2CDStereotypes.EXTERNAL_TYPE.toString())) .filter(value -> value.getValue().equals(superType)) .count() <= 0; } public static String getDotPackageName(String packageName) { if (packageName.isEmpty() || packageName.endsWith(".")) { return packageName; } return packageName + "."; } /** * Checks if the node is part of the current language (or one of its super * languages) or if it is external (e.g. String, List, etc.) * * @param type * @return */ public static boolean isExternal(CDTypeSymbol type, String superType) { Optional<Stereotype> ster = type.getStereotype(MC2CDStereotypes.EXTERNAL_TYPE.toString()); if (ster.isPresent()) { return ster.get().getValue().equals(superType); } ; return false; } public static String getPackageName(String packageName, String suffix) { return packageName.isEmpty() ? suffix : packageName + "." + suffix; } public static String getPackageName(ASTMCGrammar astGrammar, String suffix) { String qualifiedGrammarName = astGrammar.getPackage().isEmpty() ? astGrammar.getName() : Joiner.on('.').join(Names.getQualifiedName(astGrammar.getPackage()), astGrammar.getName()); return Joiner.on('.').join(qualifiedGrammarName.toLowerCase(), suffix); } public static String getSimpleTypeNameToGenerate(String simpleName, String packageName, IterablePath targetPath) { if (existsHandwrittenClass(simpleName, packageName, targetPath)) { return simpleName + TransformationHelper.GENERATED_CLASS_SUFFIX; } return simpleName; } public static boolean existsHandwrittenClass(String simpleName, String packageName, IterablePath targetPath) { return TransformationHelper.existsHandwrittenClass(targetPath, getDotPackageName(packageName) + simpleName); } /** * TODO: Gets not transformed attribute name according to the original name in * MC grammar * * @param attributeName * @return */ public static String getNativeAttributeName(String attributeName) { if (!attributeName.startsWith(JavaNamesHelper.PREFIX_WHEN_WORD_IS_RESERVED)) { return attributeName; } return attributeName.substring(JavaNamesHelper.PREFIX_WHEN_WORD_IS_RESERVED.length()); } /** * Prints Cd4Analysis AST to the file with the extension * {@link GeneratorHelper#CD_EXTENSION} in the given subdirectory * * @param astCd - the top node of the Cd4Analysis AST * @param outputPath - output path * @param subDirectory - sub directory of the output path */ public static void prettyPrintAstCd(ASTCDCompilationUnit astCd, File outputPath, String subDirectory) { String fileName = Names.getSimpleName(astCd.getCDDefinition().getName()); storeInFile(astCd, fileName, CD_EXTENSION, outputPath, subDirectory); } /** * Prints AST node to the file with the given name and extension in the given * subdirectory of the given output directory * * @param ast - the AST node to print * @param fileName * @param fileExtension * @param outputPath * @param subDirectory */ public static void storeInFile(ASTCD4AnalysisNode ast, String fileName, String fileExtension, File outputPath, String subDirectory) { Path path = createDestinationFile(fileName, fileExtension, outputPath, subDirectory); String output = getCDPrettyPrinter().prettyprint(ast); new FileReaderWriter().storeInFile(path, output); } private static Path createDestinationFile(String fileName, String fileExtension, File outputDirectory, String subDirectory) { final Path filePath = Paths.get(subDirectory, fileName + fileExtension); return Paths.get(outputDirectory.getAbsolutePath(), filePath.toString()); } /** * This method gets all diagrams that participate in the given one by getting * (1) the class diagram itself and (2) all imported class diagrams (as well * as recursively their imported class diagrams as well). If a CD occurs twice * in this import-graph, the algorithm understands that this is exactly the * same diagram and thus <em>ignores the second</em> occurrence. Note that * this is different to the rules within a grammar - there the last occurrence * would be used, because it overrides the former declarations, but on a class * diagram level exists no overriding, because different references to a * diagram always mean the same diagram (i.e., the one on the model path with * <em>the</em> matching name). * * @param cd the class diagram to get all participating class diagrams for * @return the class diagrams starting with the current grammar and then in * order of appearance in the imports of the class diagram. */ public List<CDSymbol> getAllCds(CDSymbol cd) { List<CDSymbol> resolvedCds = new ArrayList<>(); // the cd itself resolvedCds.add(cd); resolvedCds.addAll(getAllSuperCds(cd)); return resolvedCds; } /** * This method gets all diagrams that participate in the given one by getting * (1) the class diagram itself and (2) all imported class diagrams (as well * as recursively their imported class diagrams as well). If a CD occurs twice * in this import-graph, the algorithm understands that this is exactly the * same diagram and thus <em>ignores the second</em> occurrence. Note that * this is different to the rules within a grammar - there the last occurrence * would be used, because it overrides the former declarations, but on a class * diagram level exists no overriding, because different references to a * diagram always mean the same diagram (i.e., the one on the model path with * <em>the</em> matching name). * * @param cd the class diagram to get all participating class diagrams for * @return the class diagrams starting with the current grammar and then in * order of appearance in the imports of the class diagram. */ public List<CDSymbol> getAllSuperCds(CDSymbol cd) { List<CDSymbol> resolvedCds = new ArrayList<>(); // imported cds for (String importedCdName : cd.getImports()) { Log.trace("Resolving the CD: " + importedCdName, LOG_NAME); Optional<CDSymbol> importedCd = resolveCd(importedCdName); if (!importedCd.isPresent()) { Log.error("0xA8451 The class diagram could not be resolved: " + importedCdName); } else { // recursively add imported cds /* ... and prevent duplicates. First occurrence of a grammar is used. * I.e., the algorithm understands that when one grammar is imported * multiple times by different diagrams, it is still the same diagram. * Note that this is independent from the rules within a grammar - there * the last occurrence would be used, because it overrides the former * declarations . */ List<CDSymbol> recursivImportedCds = getAllCds(importedCd.get()); for (CDSymbol recImport : recursivImportedCds) { if (!resolvedCds .stream() .filter(c -> c.getFullName().equals(recImport.getFullName())) .findAny() .isPresent()) { resolvedCds.add(recImport); } } } } return resolvedCds; } /** * TODO: Write me! * * @param cd * @return */ public List<CDSymbol> getDirectSuperCds(CDSymbol cd) { List<CDSymbol> resolvedCds = new ArrayList<>(); // the cd itself resolvedCds.add(cd); // imported cds for (String importedCdName : cd.getImports()) { Log.trace("Resolving the CD: " + importedCdName, LOG_NAME); Optional<CDSymbol> importedCd = resolveCd(importedCdName); if (!importedCd.isPresent()) { Log.error("0xA8452 The class diagram could not be resolved: " + importedCdName); } resolvedCds.add(importedCd.get()); } return resolvedCds; } public CDSymbol getCd() { Optional<CDSymbol> cdOpt = resolveCd(getQualifiedCdName()); if (!cdOpt.isPresent()) { Log.error("0xA0487 The class diagram could not be resolved: " + getQualifiedCdName()); } return cdOpt.get(); } /** * @return packageName */ public String getPackageName() { return this.packageName; } public String getQualifiedCdName() { return qualifiedName; } /** * @return superGrammars in order of appearance in the grammars extends list. */ public List<String> getSuperGrammarCds() { return this.superGrammarCds; } public boolean isAstClass(ASTCDClass clazz) { String simpleName = Names.getSimpleName(clazz.getName()); if (!simpleName.startsWith(AST_PREFIX)) { return false; } String nameToResolve = clazz.getName().contains(".") ? clazz.getName() : qualifiedName + "." + clazz.getName(); if (nameToResolve.endsWith(TransformationHelper.GENERATED_CLASS_SUFFIX)) { nameToResolve = nameToResolve.substring(0, nameToResolve.lastIndexOf(TransformationHelper.GENERATED_CLASS_SUFFIX)); } return resolveCdType(nameToResolve).isPresent(); } public String getCdName() { return cdDefinition.getName(); } /** * Resolves the CD of the given qualified name * * @param qualifiedCdName full qualified name to resolve the CD for * @return the {@link CDSymbol} */ public Optional<CDSymbol> resolveCd(String qualifiedCdName) { return symbolTable.resolve(qualifiedCdName, CDSymbol.KIND); } public Optional<CDTypeSymbol> resolveCdType(String type) { // Log.trace("Resolve: " + type + " -> " + symbolTable.resolve(type, CDTypeSymbol.KIND), LOG_NAME); return symbolTable.resolve(type, CDTypeSymbol.KIND); } public static String getCdPackage(String qualifiedCdName) { return qualifiedCdName.toLowerCase(); } /** * @return cdDefinition */ public ASTCDDefinition getCdDefinition() { return this.cdDefinition; } public static String getCdName(String qualifiedCdName) { return Names.getSimpleName(qualifiedCdName); } /** * Gets the qualified java AST type for the given type. * * @param type the type symbol * @return [astPackage of the type].[type.getName()] */ public static String getJavaASTName(CDTypeSymbol type) { return AstGeneratorHelper.getAstPackage(Names.getQualifier(type.getFullName())) + type.getName(); } public static String qualifiedJavaTypeToName(String type) { return type.replace('.', '_'); } public static Multiplicity getMultiplicity(ASTMCGrammar grammar, ASTNode nonTerminal) { Multiplicity byAlternative = multiplicityByAlternative(grammar, nonTerminal); Multiplicity byIteration = multiplicityByIteration(grammar, nonTerminal); return max(Lists.newArrayList(byIteration, byAlternative)); } /** * @return the super productions defined in all super grammars (including transitive super grammars) */ public static List<ASTProd> getAllSuperProds(ASTNode astNode) { List<ASTProd> directSuperRules = getDirectSuperProds(astNode); List<ASTProd> allSuperRules = new ArrayList<>(); for (ASTProd superRule : directSuperRules) { allSuperRules.addAll(getAllSuperProds(superRule)); } allSuperRules.addAll(directSuperRules); return allSuperRules; } /** * @return the super productions defined in direct super grammars */ public static List<ASTProd> getDirectSuperProds(ASTNode astNode) { if (astNode instanceof ASTClassProd) { List<ASTProd> directSuperProds = resolveRuleReferences( ((ASTClassProd) astNode).getSuperRule(), astNode); directSuperProds.addAll( resolveRuleReferences(((ASTClassProd) astNode).getSuperInterfaceRule(), astNode)); return directSuperProds; } else if (astNode instanceof ASTInterfaceProd) { return resolveRuleReferences(((ASTInterfaceProd) astNode).getSuperInterfaceRule(), astNode); } return Collections.emptyList(); } /** * @return the production definitions of B & C in "A extends B, C" */ public static List<ASTProd> resolveRuleReferences(List<ASTRuleReference> ruleReferences, ASTNode nodeWithSymbol) { List<ASTProd> superRuleNodes = new ArrayList<>(); for (ASTRuleReference superRule : ruleReferences) { Optional<MCProdSymbol> symbol = MCGrammarSymbolTableHelper.resolveRule(nodeWithSymbol, superRule.getName()); if (symbol.isPresent() && symbol.get().getAstNode().isPresent()) { superRuleNodes.add((ASTProd) symbol.get().getAstNode().get()); } } return superRuleNodes; } public static Map<ASTProd, List<ASTNonTerminal>> getInheritedNonTerminals(ASTProd sourceNode) { return GeneratorHelper.getAllSuperProds(sourceNode).stream() .distinct() .collect(Collectors.toMap(Function.identity(), astProd -> ASTNodes.getSuccessors(astProd, ASTNonTerminal.class))); } /** * Generates an error code suffix in format "_ddd" where d is a decimal. If * there is an ast-name then always the same error code will be generated. * * @param ast * @return generated error code suffix in format "_ddd" where d is a decimal. */ public static String getGeneratedErrorCode(ASTNode ast) { int hashCode = 0; // If there is an ast-name then always generate the same error code. if (ast.getSymbol().isPresent()) { String nodeName = ast.getSymbol().get().getFullName(); hashCode = Math.abs(ast.getClass().getSimpleName().hashCode() + nodeName.hashCode()); } else { // Else use the string representation hashCode = Math.abs(ast.toString().hashCode()); } String errorCodeSuffix = String.valueOf(hashCode); return "_" + (hashCode < 1000 ? errorCodeSuffix : errorCodeSuffix .substring(errorCodeSuffix.length() - 3)); } /** * Creates an instance of the generator helper * * @param astClassDiagram * @param globalScope * @param emfCompatible * @return */ public static AstGeneratorHelper createGeneratorHelper(ASTCDCompilationUnit astClassDiagram, GlobalScope globalScope, boolean emfCompatible) { if (emfCompatible) { return new AstEmfGeneratorHelper(astClassDiagram, globalScope); } return new AstGeneratorHelper(astClassDiagram, globalScope); } }