/*
* ******************************************************************************
* 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.cd2java.ast;
import static com.google.common.collect.Lists.newArrayList;
import static de.se_rwth.commons.Names.getQualifier;
import static de.se_rwth.commons.Names.getSimpleName;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import de.monticore.ast.ASTNode;
import de.monticore.codegen.GeneratorHelper;
import de.monticore.codegen.cd2java.visitor.VisitorGeneratorHelper;
import de.monticore.codegen.mc2cd.TransformationHelper;
import de.monticore.codegen.mc2cd.MC2CDStereotypes;
import de.monticore.codegen.mc2cd.TransformationHelper;
import de.monticore.codegen.mc2cd.manipul.BaseInterfaceAddingManipulation;
import de.monticore.codegen.mc2cd.transl.ConstantsTranslation;
import de.monticore.codegen.symboltable.SymbolTableGeneratorHelper;
import de.monticore.generating.templateengine.GlobalExtensionManagement;
import de.monticore.generating.templateengine.HookPoint;
import de.monticore.generating.templateengine.StringHookPoint;
import de.monticore.generating.templateengine.TemplateHookPoint;
import de.monticore.io.paths.IterablePath;
import de.monticore.symboltable.GlobalScope;
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.ASTCDAttribute;
import de.monticore.umlcd4a.cd4analysis._ast.ASTCDClass;
import de.monticore.umlcd4a.cd4analysis._ast.ASTCDCompilationUnit;
import de.monticore.umlcd4a.cd4analysis._ast.ASTCDConstructor;
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.ASTCDParameter;
import de.monticore.umlcd4a.cd4analysis._ast.ASTCDType;
import de.monticore.umlcd4a.cd4analysis._ast.ASTModifier;
import de.monticore.umlcd4a.cd4analysis._ast.CD4AnalysisNodeFactory;
import de.monticore.umlcd4a.cd4analysis._visitor.CD4AnalysisInheritanceVisitor;
import de.monticore.umlcd4a.symboltable.CDSymbol;
import de.monticore.umlcd4a.symboltable.CDTypeSymbol;
import de.se_rwth.commons.Names;
import de.se_rwth.commons.logging.Log;
import groovyjarjarantlr.ANTLRException;
import transformation.ast.ASTCDTransformation;
/**
* Decorates class diagrams by adding of new classes and methods using in ast
* files
*
* @author (last commit) $Author$
* @version $Revision$, $Date$
*/
public class CdDecorator {
public static final String DIR_REPORTS = "_reports";
public static final String THIS_PREFIX = String.format("%n%15cthis.", ' ');
/**
* The qualified name of the empty method body template
*/
public static final String EMPTY_BODY_TEMPLATE = "ast.EmptyMethodBody";
public static final String CLASS_CONTENT_TEMPLATE = "ast.ClassContent";
public static final String ERROR_IFNULL_TEMPLATE = "ast.ErrorIfNull";
public static final String NODE_FACTORY = "NodeFactory";
protected static final String DEL = ", ";
protected ASTCDTransformation cdTransformation = new ASTCDTransformation();
protected GlobalExtensionManagement glex;
protected IterablePath targetPath;
protected GlobalScope symbolTable;
public CdDecorator(
GlobalExtensionManagement glex,
GlobalScope symbolTable,
IterablePath targetPath) {
this.glex = glex;
this.symbolTable = symbolTable;
this.targetPath = targetPath;
}
public void decorate(ASTCDCompilationUnit cdCompilationUnit) {
AstGeneratorHelper astHelper = new AstGeneratorHelper(cdCompilationUnit, symbolTable);
ASTCDDefinition cdDefinition = cdCompilationUnit.getCDDefinition();
List<ASTCDClass> nativeClasses = Lists.newArrayList(cdDefinition.getCDClasses());
// Run over classdiagramm and converts cd types to mc-java types
new Cd2JavaTypeConverter(astHelper).handle(cdDefinition);
// Interface for all ast nodes of the language
decorateBaseInterface(cdDefinition);
// Decorate with builder pattern
addBuilders(cdDefinition, astHelper);
addNodeFactoryClass(cdCompilationUnit, nativeClasses, astHelper);
// Check if handwritten ast types exist
transformCdTypeNamesForHWTypes(cdCompilationUnit);
cdDefinition.getCDClasses().stream().forEach(c -> addSuperInterfaces(c));
// Decorate with additional methods and attributes
for (ASTCDClass clazz : nativeClasses) {
addConstructors(clazz, astHelper);
addAdditionalMethods(clazz, astHelper);
// addAdditionalAttributes(clazz, astHelper);
addGetter(clazz, astHelper);
addSetter(clazz, astHelper);
addSymbolGetter(clazz, astHelper);
}
for (ASTCDInterface interf : cdDefinition.getCDInterfaces()) {
addGetter(interf);
}
// Add ASTConstant class
addConstantsClass(cdDefinition, astHelper);
// Additional imports
cdCompilationUnit.getImportStatements().add(
ASTImportStatement
.getBuilder()
.importList(
Lists.newArrayList(VisitorGeneratorHelper.getQualifiedVisitorType(astHelper
.getPackageName(), cdDefinition.getName())))
.build());
}
protected void addSymbolGetter(ASTCDClass clazz, AstGeneratorHelper astHelper) {
List<ASTCDAttribute> attributes = Lists.newArrayList(clazz.getCDAttributes());
for (ASTCDAttribute attribute : attributes) {
if (GeneratorHelper.isInherited(attribute)
|| !CD4AnalysisHelper.hasStereotype(attribute,
MC2CDStereotypes.REFERENCED_SYMBOL.toString())) {
continue;
}
// TODO PN use a general helper function
// TODO PN use import statements instead of qualified names
String referencedSymbol = CD4AnalysisHelper.getStereotypeValues(attribute,
MC2CDStereotypes.REFERENCED_SYMBOL.toString()).get(0);
if (!getQualifier(referencedSymbol).isEmpty()) {
referencedSymbol = SymbolTableGeneratorHelper
.getQualifiedSymbolType(getQualifier(referencedSymbol)
.toLowerCase(), getSimpleName(referencedSymbol));
}
String returnType;
String nameSuffix;
if (astHelper.isListAstNode(attribute)) {
returnType = "java.util.Collection<" + referencedSymbol + ">";
nameSuffix = "Symbols";
}
else {
returnType = "Optional<" + referencedSymbol + ">";
nameSuffix = "Symbol";
}
// TODO PN handle both from:Name@Foo and from:QualifiedName@Foo
String toParse = "public " + returnType + " "
+ GeneratorHelper.getPlainGetter(attribute) + nameSuffix + "() ;";
HookPoint getMethodBody = new TemplateHookPoint(
"ast.additionalmethods.GetReferencedSymbol", clazz,
attribute.getName(), referencedSymbol);
replaceMethodBodyTemplate(clazz, toParse, getMethodBody);
}
}
/**
* Adds common ast methods to the all classes in the class diagram
*
* @param clazz - each entry contains a class diagram class and a respective
* builder class
* @param astHelper
* @throws ANTLRException
*/
protected void addAdditionalMethods(ASTCDClass clazz,
AstGeneratorHelper astHelper) {
if (astHelper.isAstClass(clazz)) {
AstAdditionalMethods additionalMethod = AstAdditionalMethods.accept;
String visitorTypeFQN = VisitorGeneratorHelper.getQualifiedVisitorType(
astHelper.getPackageName(), astHelper.getCdName());
String methodSignatur = String.format(additionalMethod.getDeclaration(), visitorTypeFQN);
replaceMethodBodyTemplate(clazz, methodSignatur, new TemplateHookPoint(
"ast.additionalmethods.Accept"));
// node needs to accept visitors from all super languages
for (CDSymbol cdSym : astHelper.getAllSuperCds(astHelper.getCd())) {
String superGrammarName = Names.getSimpleName(cdSym.getFullName());
String visitorType = superGrammarName + "Visitor";
String visitorPackage = VisitorGeneratorHelper.getVisitorPackage(cdSym.getFullName());
additionalMethod = AstAdditionalMethods.accept;
String superVisitorTypeFQN = visitorPackage + "." + visitorType;
methodSignatur = String.format(additionalMethod.getDeclaration(), superVisitorTypeFQN);
replaceMethodBodyTemplate(clazz, methodSignatur, new TemplateHookPoint(
"ast.additionalmethods.AcceptSuper", clazz, astHelper.getQualifiedCdName(),
visitorTypeFQN, superVisitorTypeFQN));
}
}
Optional<ASTModifier> modifier = clazz.getModifier();
String plainClassName = GeneratorHelper.getPlainName(clazz);
Optional<CDTypeSymbol> symbol = astHelper.getCd().getType(plainClassName);
if (!symbol.isPresent()) {
Log.error("0xA1062 CdDecorator error: Can't find symbol for class " + plainClassName);
}
replaceMethodBodyTemplate(clazz, AstAdditionalMethods.deepEqualsWithOrder.getDeclaration(),
new TemplateHookPoint("ast.additionalmethods.DeepEqualsWithOrder"));
replaceMethodBodyTemplate(clazz, AstAdditionalMethods.deepEquals.getDeclaration(),
new StringHookPoint("return deepEquals(o, true);\n"));
replaceMethodBodyTemplate(clazz,
AstAdditionalMethods.deepEqualsWithCommentsWithOrder.getDeclaration(),
new TemplateHookPoint("ast.additionalmethods.DeepEqualsWithComments"));
replaceMethodBodyTemplate(clazz,
AstAdditionalMethods.deepEqualsWithComments.getDeclaration(),
new StringHookPoint("return deepEqualsWithComments(o, true);\n"));
replaceMethodBodyTemplate(clazz, AstAdditionalMethods.equalAttributes.getDeclaration(),
new TemplateHookPoint("ast.additionalmethods.EqualAttributes"));
replaceMethodBodyTemplate(clazz, AstAdditionalMethods.equalsWithComments.getDeclaration(),
new TemplateHookPoint("ast.additionalmethods.EqualsWithComments"));
replaceMethodBodyTemplate(clazz, AstAdditionalMethods.get_Children.getDeclaration(),
new TemplateHookPoint("ast.additionalmethods.GetChildren", clazz, symbol.get()));
replaceMethodBodyTemplate(clazz, AstAdditionalMethods.remove_Child.getDeclaration(),
new TemplateHookPoint("ast.additionalmethods.RemoveChild", clazz, symbol.get()));
replaceMethodBodyTemplate(clazz, AstAdditionalMethods.getBuilder.getDeclaration(),
new StringHookPoint("return new Builder();\n"));
String stringToParse = String.format(AstAdditionalMethods.deepClone.getDeclaration(),
plainClassName);
replaceMethodBodyTemplate(clazz, stringToParse,
new StringHookPoint("return deepClone(_construct());\n"));
stringToParse = String.format(AstAdditionalMethods.deepCloneWithOrder.getDeclaration(),
plainClassName, plainClassName);
replaceMethodBodyTemplate(clazz, stringToParse,
new TemplateHookPoint("ast.additionalmethods.DeepCloneWithParameters"));
if (modifier.isPresent() && modifier.get().isAbstract()) {
stringToParse = String.format(AstAdditionalMethods._construct.getDeclaration(), "abstract "
+ plainClassName);
cdTransformation.addCdMethodUsingDefinition(clazz, stringToParse);
}
else {
stringToParse = String.format(AstAdditionalMethods._construct.getDeclaration(),
plainClassName);
replaceMethodBodyTemplate(clazz, stringToParse,
new StringHookPoint("return new " + plainClassName + "();\n"));
}
}
/**
* Decorates class diagram with builder pattern for all classes excepting
* lists
*
* @param cdDefinition
* @param astHelper
* @throws ANTLRException
*/
protected void addBuilders(ASTCDDefinition cdDefinition, AstGeneratorHelper astHelper) {
newArrayList(cdDefinition.getCDClasses()).stream()
.forEach(c -> cdTransformation.addCdClassUsingDefinition(cdDefinition,
"public static class " + AstGeneratorHelper.getNameOfBuilderClass(c) + " ;"));
}
protected void addSuperInterfaces(ASTCDClass clazz) {
String interfaces = clazz.printInterfaces();
if (!interfaces.isEmpty()) {
glex.replaceTemplate("ast.AstSuperInterfaces", clazz,
new StringHookPoint(interfaces + DEL));
}
}
/**
* TODO: Write me!
*
* @param clazz
* @param astHelper
* @throws ANTLRException
*/
protected void addAdditionalAttributes(
ASTCDClass clazz, AstGeneratorHelper astHelper) {
// Add Symbol attribute
cdTransformation.addCdAttributeUsingDefinition(clazz,
AstAdditionalAttributes.symbol.getDeclaration());
// Add Scope attribute
cdTransformation.addCdAttributeUsingDefinition(clazz,
AstAdditionalAttributes.enclosingScope.getDeclaration());
}
/**
* Adds getter for all attributes of ast classes
*
* @param interf
* @param astHelper
* @throws ANTLRException
*/
protected void addGetter(ASTCDClass clazz, AstGeneratorHelper astHelper) {
List<ASTCDAttribute> attributes = Lists.newArrayList(clazz.getCDAttributes());
// attributes.addAll(astHelper.getAttributesOfExtendedInterfaces(clazz));
for (ASTCDAttribute attribute : attributes) {
if (GeneratorHelper.isInherited(attribute)) {
continue;
}
String methodName = GeneratorHelper.getPlainGetter(attribute);
if (clazz.getCDMethods().stream()
.filter(m -> methodName.equals(m.getName()) && m.getCDParameters().isEmpty()).findAny()
.isPresent()) {
continue;
}
String toParse = "public " + TypesPrinter.printType(attribute.getType()) + " "
+ methodName + "() ;";
HookPoint getMethodBody = new TemplateHookPoint("ast.additionalmethods.Get", clazz,
attribute.getName());
replaceMethodBodyTemplate(clazz, toParse, getMethodBody);
}
}
/**
* TODO: Write me!
*
* @param interf
* @param astHelper
* @param glex
*/
protected void addGetter(ASTCDInterface interf) {
for (ASTCDAttribute attribute : interf.getCDAttributes()) {
if (GeneratorHelper.isInherited(attribute)) {
continue;
}
String methodName = GeneratorHelper.getPlainGetter(attribute);
if (interf.getCDMethods().stream()
.filter(m -> methodName.equals(m.getName()) && m.getCDParameters().isEmpty()).findAny()
.isPresent()) {
continue;
}
String toParse = "public " + TypesPrinter.printType(attribute.getType()) + " "
+ GeneratorHelper.getPlainGetter(attribute) + "();";
cdTransformation.addCdMethodUsingDefinition(interf, toParse);
}
}
/**
* Adds getter for all attributes of ast classes
*
* @param clazz
* @param astHelper
* @throws ANTLRException
*/
protected void addSetter(ASTCDClass clazz, AstGeneratorHelper astHelper) {
for (ASTCDAttribute attribute : clazz.getCDAttributes()) {
String typeName = TypesHelper.printSimpleRefType(attribute.getType());
if (!AstGeneratorHelper.generateSetter(clazz, attribute, typeName)) {
continue;
}
String attributeName = attribute.getName();
String methodName = GeneratorHelper.getPlainSetter(attribute);
boolean isOptional = GeneratorHelper.isOptional(attribute);
String toParse = "public void " + methodName + "("
+ typeName + " " + attributeName + ") ;";
HookPoint methodBody = new TemplateHookPoint("ast.additionalmethods.Set", clazz,
attribute, attributeName);
ASTCDMethod setMethod = replaceMethodBodyTemplate(clazz, toParse, methodBody);
if (isOptional) {
glex.replaceTemplate(ERROR_IFNULL_TEMPLATE, setMethod, new StringHookPoint(""));
}
if (isOptional) {
toParse = "public boolean " + attributeName + "IsPresent() ;";
methodBody = new StringHookPoint(" return " + attributeName + ".isPresent(); \n");
replaceMethodBodyTemplate(clazz, toParse, methodBody);
}
}
}
/**
* TODO: Write me!
*
* @param cdCompilationUnit
* @param nativeClasses
* @param astHelper
* @throws ANTLRException
*/
protected void addNodeFactoryClass(ASTCDCompilationUnit cdCompilationUnit,
List<ASTCDClass> nativeClasses, AstGeneratorHelper astHelper) {
// Add factory-attributes for all ast classes
Set<String> astClasses = new LinkedHashSet<>();
nativeClasses.stream()
.forEach(e -> astClasses.add(GeneratorHelper.getPlainName(e)));
ASTCDClass nodeFactoryClass = createNodeFactoryClass(cdCompilationUnit, nativeClasses,
astHelper, astClasses);
List<String> imports = getImportsForNodeFactory(nodeFactoryClass, astClasses, astHelper);
glex.replaceTemplate(CLASS_CONTENT_TEMPLATE, nodeFactoryClass, new TemplateHookPoint(
"ast.AstNodeFactory", nodeFactoryClass, imports));
}
protected ASTCDClass createNodeFactoryClass(ASTCDCompilationUnit cdCompilationUnit,
List<ASTCDClass> nativeClasses, AstGeneratorHelper astHelper, Set<String> astClasses) {
ASTCDDefinition cdDef = cdCompilationUnit.getCDDefinition();
ASTCDClass nodeFactoryClass = CD4AnalysisNodeFactory.createASTCDClass();
String nodeFactoryName = cdDef.getName() + NODE_FACTORY;
// Check if a handwritten node factory exists
if (TransformationHelper.existsHandwrittenClass(targetPath,
TransformationHelper.getAstPackageName(cdCompilationUnit)
+ nodeFactoryName)) {
nodeFactoryName += TransformationHelper.GENERATED_CLASS_SUFFIX;
}
nodeFactoryClass.setName(nodeFactoryName);
for (String clazz : astClasses) {
String toParse = "protected static " + nodeFactoryName + " factory" + clazz + " = null;";
cdTransformation.addCdAttributeUsingDefinition(nodeFactoryClass, toParse);
}
// Add ast-creating methods
for (ASTCDClass clazz : nativeClasses) {
addMethodsToNodeFactory(clazz, nodeFactoryClass, astHelper);
}
cdDef.getCDClasses().add(nodeFactoryClass);
return nodeFactoryClass;
}
protected List<String> getImportsForNodeFactory(ASTCDClass nodeFactoryClass,
Set<String> astClasses, AstGeneratorHelper astHelper) {
String nodeFactoryName = nodeFactoryClass.getName();
// Add delegating methods for creating of the ast nodes of the super
// grammars
List<String> imports = new ArrayList<>();
if (!astHelper.getSuperGrammarCds().isEmpty()) {
for (CDSymbol superCd : astHelper.getAllCds(astHelper.getCdSymbol())) {
Log.debug(" CDSymbol for " + nodeFactoryName + " : " + superCd, "CdDecorator");
nodeFactoryName = getSimpleName(superCd.getName()) + NODE_FACTORY;
String factoryPackage = superCd.getFullName().toLowerCase()
+ AstGeneratorHelper.AST_DOT_PACKAGE_SUFFIX_DOT;
imports.add(factoryPackage + "*");
for (CDTypeSymbol type : superCd.getTypes()) {
Optional<ASTNode> node = type.getAstNode();
if (node.isPresent() && node.get() instanceof ASTCDClass) {
ASTCDClass cdClass = (ASTCDClass) node.get();
if (astClasses.contains(cdClass.getName())) {
continue;
}
astClasses.add(cdClass.getName());
addDelegateMethodsToNodeFactory(cdClass, nodeFactoryClass, astHelper, superCd,
factoryPackage + nodeFactoryName);
}
}
}
}
return imports;
}
/**
* TODO: Write me!
*
* @param astHelper
* @param cdClass
* @param nodeFactoryForSuperCd
*/
protected void addMethodsToNodeFactory(ASTCDClass clazz, ASTCDClass nodeFactoryClass,
AstGeneratorHelper astHelper) {
if (!clazz.getModifier().isPresent() || clazz.getModifier().get().isAbstract()) {
return;
}
String className = GeneratorHelper.getPlainName(clazz);
String toParse = "public static " + className + " create" + className + "() ;";
HookPoint methodBody = new TemplateHookPoint("ast.factorymethods.Create", clazz, className);
replaceMethodBodyTemplate(nodeFactoryClass, toParse, methodBody);
toParse = "protected " + className + " doCreate" + className + "() ;";
methodBody = new TemplateHookPoint("ast.factorymethods.DoCreate", clazz, className);
replaceMethodBodyTemplate(nodeFactoryClass, toParse, methodBody);
// No create methods with parameters
if (clazz.getCDAttributes().isEmpty()) {
return;
}
toParse = "public static " + className + " create" + className + "() ;";
Optional<ASTCDMethod> astMethod = cdTransformation.addCdMethodUsingDefinition(
nodeFactoryClass, toParse);
Preconditions.checkArgument(astMethod.isPresent());
ASTCDMethod createMethod = astMethod.get();
toParse = "protected " + className + " doCreate" + className + "() ;";
astMethod = cdTransformation.addCdMethodUsingDefinition(
nodeFactoryClass, toParse);
Preconditions.checkArgument(astMethod.isPresent());
ASTCDMethod doCreateMethod = astMethod.get();
StringBuilder paramCall = new StringBuilder();
List<ASTCDAttribute> parameters = Lists.newArrayList();
String del = "";
List<ASTCDAttribute> inheritedAttributes = Lists.newArrayList();
for (ASTCDAttribute attr : clazz.getCDAttributes()) {
if (GeneratorHelper.isInherited(attr)) {
inheritedAttributes.add(attr);
continue;
}
ASTCDParameter param = CD4AnalysisNodeFactory.createASTCDParameter();
ASTType type = attr.getType();
if (TypesHelper.isOptional(type)) {
type = TypesHelper.getSimpleReferenceTypeFromOptional(type);
}
else {
parameters.add(attr);
}
param.setType(type);
String javaAttrName = GeneratorHelper.getJavaAndCdConformName(attr.getName());
param.setName(javaAttrName);
ASTCDParameter doParam = param.deepClone();
createMethod.getCDParameters().add(param);
doCreateMethod.getCDParameters().add(doParam);
paramCall.append(del + javaAttrName);
del = DEL;
}
for (ASTCDAttribute attr : inheritedAttributes) {
ASTCDParameter param = CD4AnalysisNodeFactory.createASTCDParameter();
ASTType type = attr.getType();
if (TypesHelper.isOptional(type)) {
type = TypesHelper.getSimpleReferenceTypeFromOptional(type);
}
else {
parameters.add(attr);
}
param.setType(type);
String javaAttrName = GeneratorHelper.getJavaAndCdConformName(attr.getName());
param.setName(javaAttrName);
ASTCDParameter doParam = param.deepClone();
createMethod.getCDParameters().add(param);
doCreateMethod.getCDParameters().add(doParam);
paramCall.append(del + javaAttrName);
del = DEL;
}
// create() method
glex.replaceTemplate("ast.ParametersDeclaration", createMethod, new TemplateHookPoint(
"ast.ConstructorParametersDeclaration"));
glex.replaceTemplate(EMPTY_BODY_TEMPLATE, createMethod, new TemplateHookPoint(
"ast.factorymethods.CreateWithParams", clazz, className, paramCall.toString()));
// doCreate() method
glex.replaceTemplate("ast.ParametersDeclaration", doCreateMethod, new TemplateHookPoint(
"ast.ConstructorParametersDeclaration"));
glex.replaceTemplate(EMPTY_BODY_TEMPLATE, doCreateMethod, new TemplateHookPoint(
"ast.factorymethods.DoCreateWithParams", clazz, className, paramCall.toString()));
if (parameters.size() != createMethod.getCDParameters().size()) {
glex.replaceTemplate(ERROR_IFNULL_TEMPLATE, createMethod, new TemplateHookPoint(
"ast.factorymethods.ErrorIfNull", parameters));
}
if (parameters.size() != doCreateMethod.getCDParameters().size()) {
glex.replaceTemplate(ERROR_IFNULL_TEMPLATE, doCreateMethod, new TemplateHookPoint(
"ast.factorymethods.ErrorIfNull", parameters));
}
}
/**
* TODO: Write me!
*
* @param astHelper
* @param cdSymbol
* @param delegateFactoryName
* @param cdClass
* @param nodeFactoryForSuperCd
*/
protected void addDelegateMethodsToNodeFactory(ASTCDClass clazz, ASTCDClass nodeFactoryClass,
AstGeneratorHelper astHelper, CDSymbol cdSymbol, String delegateFactoryName) {
if (!clazz.getModifier().isPresent() || clazz.getModifier().get().isAbstract()) {
return;
}
String className = GeneratorHelper.getPlainName(clazz);
String toParse = "public static " + cdSymbol.getFullName().toLowerCase()
+ AstGeneratorHelper.AST_DOT_PACKAGE_SUFFIX_DOT + className + " create" + className
+ "() ;";
HookPoint methodBody = new TemplateHookPoint("ast.factorymethods.CreateDelegate",
delegateFactoryName, className);
replaceMethodBodyTemplate(nodeFactoryClass, toParse, methodBody);
// No create methods with parameters (only additional attributes {@link
// AstAdditionalAttributes}
if (clazz.getCDAttributes().size() <= 2) {
return;
}
Optional<ASTCDMethod> astMethod = cdTransformation.addCdMethodUsingDefinition(
nodeFactoryClass, toParse);
Preconditions.checkArgument(astMethod.isPresent());
ASTCDMethod createMethod = astMethod.get();
StringBuilder paramCall = new StringBuilder();
String del = "";
List<ASTCDAttribute> inheritedAttributes = Lists.newArrayList();
for (ASTCDAttribute attr : clazz.getCDAttributes()) {
if (GeneratorHelper.isInherited(attr)) {
inheritedAttributes.add(attr);
continue;
}
if (Arrays.asList(AstAdditionalAttributes.values()).stream().map(a -> a.toString())
.anyMatch(a -> a.equals(attr.getName()))) {
continue;
}
ASTCDParameter param = CD4AnalysisNodeFactory.createASTCDParameter();
ASTType type = attr.getType();
if (TypesHelper.isOptional(type)) {
type = TypesHelper.getSimpleReferenceTypeFromOptional(type);
}
if (type instanceof ASTSimpleReferenceType) {
type = astHelper.convertTypeCd2Java((ASTSimpleReferenceType) type,
AstGeneratorHelper.AST_DOT_PACKAGE_SUFFIX_DOT);
}
param.setType(type);
String javaAttrName = GeneratorHelper.getJavaAndCdConformName(attr.getName());
param.setName(javaAttrName);
createMethod.getCDParameters().add(param);
paramCall.append(del + javaAttrName);
del = DEL;
}
for (ASTCDAttribute attr : inheritedAttributes) {
ASTCDParameter param = CD4AnalysisNodeFactory.createASTCDParameter();
ASTType type = attr.getType();
if (TypesHelper.isOptional(type)) {
type = TypesHelper.getSimpleReferenceTypeFromOptional(type);
}
if (type instanceof ASTSimpleReferenceType) {
type = astHelper.convertTypeCd2Java((ASTSimpleReferenceType) type,
AstGeneratorHelper.AST_PACKAGE_SUFFIX);
}
param.setType(type);
String javaAttrName = GeneratorHelper.getJavaAndCdConformName(attr.getName());
param.setName(javaAttrName);
createMethod.getCDParameters().add(param);
paramCall.append(del + javaAttrName);
del = DEL;
}
// create() method
glex.replaceTemplate("ast.ParametersDeclaration", createMethod, new TemplateHookPoint(
"ast.ConstructorParametersDeclaration"));
glex.replaceTemplate(EMPTY_BODY_TEMPLATE, createMethod,
new TemplateHookPoint(
"ast.factorymethods.CreateWithParamsDelegate", delegateFactoryName, className,
paramCall.toString()));
glex.replaceTemplate(ERROR_IFNULL_TEMPLATE, createMethod, new StringHookPoint(""));
}
/**
* TODO: Write me!
*
* @param clazz
* @param astHelper
*/
protected void addConstructors(ASTCDClass clazz,
AstGeneratorHelper astHelper) {
ASTCDConstructor emptyConstructor = CD4AnalysisNodeFactory.createASTCDConstructor();
emptyConstructor.setName(clazz.getName());
emptyConstructor.setModifier(TransformationHelper.createProtectedModifier());
clazz.getCDConstructors().add(emptyConstructor);
// Only one constructor
if (clazz.getCDAttributes().isEmpty()) {
return;
}
ASTCDConstructor fullConstructor = emptyConstructor.deepClone();
// TODO: Collect parameters of the super class (Symbol table)
List<ASTCDAttribute> inheritedAttributes = Lists.newArrayList();
for (ASTCDAttribute attr : clazz.getCDAttributes()) {
if (GeneratorHelper.isInherited(attr)) {
inheritedAttributes.add(attr);
continue;
}
ASTCDParameter param = CD4AnalysisNodeFactory.createASTCDParameter();
param.setType((ASTType) attr.getType().deepClone());
param.setName(attr.getName());
fullConstructor.getCDParameters().add(param);
}
for (ASTCDAttribute attr : inheritedAttributes) {
ASTCDParameter param = CD4AnalysisNodeFactory.createASTCDParameter();
param.setType((ASTType) attr.getType().deepClone());
param.setName(attr.getName());
fullConstructor.getCDParameters().add(param);
}
clazz.getCDConstructors().add(fullConstructor);
glex.replaceTemplate("ast.ParametersDeclaration", fullConstructor, new TemplateHookPoint(
"ast.ConstructorParametersDeclaration"));
glex.replaceTemplate("ast.EmptyMethodBody", fullConstructor, new TemplateHookPoint(
"ast.ConstructorAttributesSetter"));
Optional<ASTCDClass> clazzBuilder = astHelper.getASTBuilder(clazz);
if (clazzBuilder.isPresent()) {
glex.replaceTemplate(
"ast.ParametersDeclaration",
clazzBuilder.get(),
new TemplateHookPoint(
"ast.BuilderConstructorParametersDeclaration", fullConstructor.getCDParameters()));
}
}
/**
* TODO: Write me!
*
* @param cdDefinition
* @param astHelper
* @throws ANTLRException
*/
protected void addConstantsClass(ASTCDDefinition cdDefinition, AstGeneratorHelper astHelper) {
String enumLiterals = cdDefinition.getName() + ConstantsTranslation.CONSTANTS_ENUM;
Optional<ASTCDEnum> enumConstans = cdDefinition.getCDEnums().stream()
.filter(e -> e.getName().equals(enumLiterals)).findAny();
if (!enumConstans.isPresent()) {
Log.error("0xA1004 CdDecorator error: " + enumLiterals
+ " class can't be created for the class diagramm "
+ cdDefinition.getName());
return;
}
String constantsClassName = "ASTConstants" + cdDefinition.getName();
Optional<ASTCDClass> ast = cdTransformation.addCdClassUsingDefinition(cdDefinition,
"public class " + constantsClassName + ";");
if (!ast.isPresent()) {
Log.error("0xA1028 CdDecorator error:" + constantsClassName
+ " class can't be created for the class diagramm "
+ cdDefinition.getName());
return;
}
ASTCDClass astConstantsClass = ast.get();
glex.replaceTemplate(
CLASS_CONTENT_TEMPLATE,
astConstantsClass,
new TemplateHookPoint(
"ast.ASTConstantsClass", astConstantsClass, astHelper.getQualifiedCdName(), astHelper
.getSuperGrammarCds()));
for (ASTCDEnumConstant astConstant : enumConstans.get().getCDEnumConstants()) {
ASTCDAttribute constAttr = CD4AnalysisNodeFactory.createASTCDAttribute();
constAttr.setName(astConstant.getName());
astConstantsClass.getCDAttributes().add(constAttr);
}
// cdDefinition.getCDEnums().remove(enumConstans.get());
}
/**
* TODO: Write me!
*
* @param cdDefinition
* @param astHelper
*/
protected void decorateBaseInterface(ASTCDDefinition cdDefinition) {
List<ASTCDInterface> stream = cdDefinition
.getCDInterfaces()
.stream()
.filter(
i -> i.getName().equals(
BaseInterfaceAddingManipulation.getBaseInterfaceName(cdDefinition)))
.collect(Collectors.toList());
if (stream.size() != 1) {
Log.error("0xA3002 error by generation of the base node interface for the grammar "
+ cdDefinition.getName());
return;
}
ASTCDInterface baseInterface = stream.get(0);
baseInterface.getInterfaces().add(
TransformationHelper.createSimpleReference(GeneratorHelper.AST_NODE));
glex.replaceTemplate(
"ast.AstInterfaceContent",
baseInterface,
new TemplateHookPoint(
"ast.ASTNodeBase", baseInterface));
}
/**
* TODO: Write me!
*
* @param cdCompilationUnit
*/
protected void transformCdTypeNamesForHWTypes(ASTCDCompilationUnit cdCompilationUnit) {
String packageName = TransformationHelper.getAstPackageName(cdCompilationUnit);
cdCompilationUnit
.getCDDefinition()
.getCDClasses()
.forEach(
c -> c.setName(GeneratorHelper.getSimpleTypeNameToGenerate(c.getName(), packageName,
targetPath)));
cdCompilationUnit
.getCDDefinition()
.getCDInterfaces()
.forEach(
c -> c.setName(GeneratorHelper.getSimpleTypeNameToGenerate(c.getName(), packageName,
targetPath)));
cdCompilationUnit
.getCDDefinition()
.getCDEnums()
.forEach(
c -> c.setName(GeneratorHelper.getSimpleTypeNameToGenerate(c.getName(), packageName,
targetPath)));
}
/**
* Performs ast specific template replacements using {@link HookPoint}
*
* @param ast
* @param replacedTemplateName qualified name of template to be replaced
* @param glex
*/
public ASTCDMethod replaceMethodBodyTemplate(ASTCDType clazz, String methodSignatur,
HookPoint hookPoint) {
Optional<ASTCDMethod> astMethod = cdTransformation.addCdMethodUsingDefinition(clazz,
methodSignatur);
Preconditions.checkArgument(astMethod.isPresent());
glex.replaceTemplate(EMPTY_BODY_TEMPLATE, astMethod.get(), hookPoint);
return astMethod.get();
}
/**
* Converts all CD types [(qualified)Classdiagramm.Type] to MontiCore-Java
* types [qualified AST-Type] e.g. Literals.ASTIntLiteral (oder
* de.monticore.literals.Literals.ASTIntLiteral) will be converted to
* de.monticore.literals.literals._ast.ASTIntLiteral
*/
public class Cd2JavaTypeConverter implements CD4AnalysisInheritanceVisitor {
private AstGeneratorHelper astHelper;
public Cd2JavaTypeConverter(AstGeneratorHelper astHelper) {
this.astHelper = astHelper;
}
@Override
public void visit(ASTSimpleReferenceType ast) {
astHelper.transformTypeCd2Java(ast, GeneratorHelper.AST_DOT_PACKAGE_SUFFIX_DOT);
}
}
}