Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ public ChainableGenSetup withObservers() {
return this.withDecorator(new ObserverDecorator());
}

public ChainableGenSetup withVisitors() {
return this.withDecorator(new VisitorDecorator());
}

public ChainableGenSetup withVisitorImplementations() {
return this.withDecorator(new VisitorImplementationDecorator());
}

@SuppressWarnings("unchecked")
public ChainableGenSetup withDecorator(String className) {
IDecorator<?> newObj = (IDecorator<?>) ObjectFactory.createObject(className);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import static de.monticore.cd.codegen.CD2JavaTemplates.EMPTY_BODY;

import de.monticore.cd.codegen.decorators.data.AbstractDecorator;
import de.monticore.cd.codegen.decorators.data.DecoratorData;
import de.monticore.cd.facade.CDMethodFacade;
import de.monticore.cd.methodtemplates.CD4C;
import de.monticore.cd4code._prettyprint.CD4CodeFullPrettyPrinter;
Expand All @@ -13,6 +14,7 @@
import de.monticore.cdbasis._ast.ASTCDAttribute;
import de.monticore.cdbasis._ast.ASTCDClass;
import de.monticore.cdbasis._visitor.CDBasisVisitor2;
import de.monticore.generating.templateengine.GlobalExtensionManagement;
import de.monticore.generating.templateengine.HookPoint;
import de.monticore.generating.templateengine.TemplateHookPoint;
import de.monticore.prettyprint.IndentPrinter;
Expand All @@ -21,17 +23,26 @@
import de.monticore.types.mccollectiontypes.types3.MCCollectionSymTypeRelations;
import de.se_rwth.commons.StringTransformations;
import de.se_rwth.commons.logging.Log;
import java.util.Arrays;

import java.util.*;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;

/**
* Add get methods to all attributes <a
* href="https://mbse.se-rwth.de/book2/index.php?c=chapter5-1">methodic</a>
*/
public class GetterDecorator extends AbstractDecorator<AbstractDecorator.NoData> implements
public class GetterDecorator extends AbstractDecorator<GetterDecorator.GetterData> implements
CDBasisVisitor2 {

protected GetterData getterData;

@Override
public void init(DecoratorData util, Optional<GlobalExtensionManagement> glexOpt) {
super.init(util, glexOpt);
this.getterData = this.decoratorData.createDataIfAbsent(this.getClass(), GetterData::new);
}

@Override
public void visit(ASTCDAttribute attribute) {
// First, check if we should decorate the given object
Expand All @@ -41,26 +52,29 @@ public void visit(ASTCDAttribute attribute) {
//
var decClazz = (ASTCDClass) decoratorData.getAsDecorated(originalClazz);
if (MCTypeFacade.getInstance().isBooleanType(attribute.getMCType())) {
decorateMandatory(decClazz, attribute);
this.getterData.getOrCreateMethods(attribute).add(decorateMandatory(decClazz, attribute));
}
else if (MCCollectionSymTypeRelations.isList(attribute.getSymbol().getType())) {
decorateList(decClazz, attribute);
this.getterData.getOrCreateMethods(attribute).add(decorateList(decClazz, attribute));
decorateWithAssocFunctions(decClazz, attribute, true);
}
else if (MCCollectionSymTypeRelations.isSet(attribute.getSymbol().getType())) {
decorateSet(decClazz, attribute);
this.getterData.getOrCreateMethods(attribute).add(decorateSet(decClazz, attribute));
decorateWithAssocFunctions(decClazz, attribute, false);
}
else if (MCCollectionSymTypeRelations.isOptional(attribute.getSymbol().getType())) {
decorateOptional(decClazz, attribute);
this.getterData.getOrCreateMethods(attribute).add(decorateOptional(decClazz, attribute));
this.getterData.getOrCreateMethods(attribute).add(decorateOptionalIsPresent(decClazz,
attribute));
}
else {
decorateMandatory(decClazz, attribute);
this.getterData.getOrCreateMethods(attribute).add(decorateMandatory(decClazz, attribute));
}
}
}

protected void decorateMandatory(ASTCDClass decoratedClazz, ASTCDAttribute attribute) {
protected MethodInformation decorateMandatory(ASTCDClass decoratedClazz,
ASTCDAttribute attribute) {
String name = (MCTypeFacade.getInstance().isBooleanType(attribute.getMCType()) ? "is" : "get")
+ StringTransformations.capitalize(attribute.getName());
ASTMCType type = attribute.getMCType().deepClone();
Expand All @@ -73,9 +87,13 @@ protected void decorateMandatory(ASTCDClass decoratedClazz, ASTCDAttribute attri
addToClass(decoratedClazz, method);

this.updateModifier(attribute);

return new MethodInformation(GetterMethodKind.GET_MANDATORY_OR_OPT, method, "methods.Get",
attribute.getName());
}

protected void decorateOptional(ASTCDClass decoratedClazz, ASTCDAttribute attribute) {
protected MethodInformation decorateOptional(ASTCDClass decoratedClazz,
ASTCDAttribute attribute) {
String name = "get" + StringTransformations.capitalize(attribute.getName());
ASTMCType type = getCDGenService().getFirstTypeArgument(attribute.getMCType()).deepClone();

Expand All @@ -91,7 +109,12 @@ protected void decorateOptional(ASTCDClass decoratedClazz, ASTCDAttribute attrib
CD4C.getInstance().addImport(decoratedClazz, Log.class.getName());

addToClass(decoratedClazz, getMethod);

return new MethodInformation(GetterMethodKind.GET_MANDATORY_OR_OPT, getMethod,
"methods.opt.Get4Opt", attribute.getName());
}

protected MethodInformation decorateOptionalIsPresent(ASTCDClass decoratedClazz,
ASTCDAttribute attribute) {
ASTCDMethod isPresentMethod = CDMethodFacade.getInstance().createMethod(attribute.getModifier()
.deepClone(), MCTypeFacade.getInstance().createBooleanType(), "isPresent"
+ StringTransformations.capitalize(attribute.getName()));
Expand All @@ -100,9 +123,11 @@ protected void decorateOptional(ASTCDClass decoratedClazz, ASTCDAttribute attrib
addToClass(decoratedClazz, isPresentMethod);

this.updateModifier(attribute);
return new MethodInformation(GetterMethodKind.IS_PRESENT, isPresentMethod,
"methods.opt.IsPresent4Opt", attribute.getName());
}

protected void decorateSet(ASTCDClass decoratedClazz, ASTCDAttribute attribute) {
protected MethodInformation decorateSet(ASTCDClass decoratedClazz, ASTCDAttribute attribute) {
String name = "get" + StringTransformations.capitalize(attribute.getName());
ASTMCType type = getCDGenService().getFirstTypeArgument(attribute.getMCType()).deepClone();

Expand All @@ -114,9 +139,12 @@ protected void decorateSet(ASTCDClass decoratedClazz, ASTCDAttribute attribute)
addToClass(decoratedClazz, getListMethod);

this.updateModifier(attribute);

return new MethodInformation(GetterMethodKind.GET_COLLECTION, getListMethod, "methods.Get",
attribute.getName());
}

protected void decorateList(ASTCDClass decoratedClazz, ASTCDAttribute attribute) {
protected MethodInformation decorateList(ASTCDClass decoratedClazz, ASTCDAttribute attribute) {
String name = "get" + StringTransformations.capitalize(attribute.getName());
ASTMCType type = getCDGenService().getFirstTypeArgument(attribute.getMCType()).deepClone();

Expand All @@ -128,6 +156,8 @@ protected void decorateList(ASTCDClass decoratedClazz, ASTCDAttribute attribute)
addToClass(decoratedClazz, getListMethod);

this.updateModifier(attribute);
return new MethodInformation(GetterMethodKind.GET_COLLECTION, getListMethod, "methods.Get",
attribute.getName());
}

protected void decorateWithAssocFunctions(ASTCDClass decoratedClazz, ASTCDAttribute attribute,
Expand Down Expand Up @@ -236,4 +266,53 @@ public void addToTraverser(CD4CodeTraverser traverser) {
traverser.add4CDBasis(this);
}

public static class GetterData {

protected final Map<ASTCDAttribute, List<MethodInformation>> attributesData =
new LinkedHashMap<>();

public List<MethodInformation> getMethods(ASTCDAttribute node) {
var ret = attributesData.get(node);
if (ret == null) {
Log.warn("Requested setter of " + node.getSymbol().getFullName()
+ ", which has no setters!", node.get_SourcePositionStart());
}
return ret == null ? List.of() : ret;
}

protected List<MethodInformation> getOrCreateMethods(ASTCDAttribute node) {
return this.attributesData.computeIfAbsent(node, a -> new ArrayList<>());
}

}

public static class MethodInformation {

private final GetterMethodKind kind;
private final ASTCDMethod getMethod;
private final String templateName;
private final String paramName;

public MethodInformation(GetterMethodKind kind, ASTCDMethod setMethod, String templateName,
String paramName) {
this.kind = kind;
this.getMethod = setMethod;
this.templateName = templateName;
this.paramName = paramName;
}

public GetterMethodKind getKind() { return kind; }

public ASTCDMethod getGetMethod() { return getMethod; }

public String getTemplateName() { return templateName; }

public String getParamName() { return paramName; }

}

public enum GetterMethodKind {
GET_MANDATORY_OR_OPT, IS_PRESENT, GET_COLLECTION
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/* (c) https://github.com/MontiCore/monticore */
package de.monticore.cd.codegen.decorators;

import com.google.common.collect.Iterables;
import de.monticore.ast.ASTNode;
import de.monticore.cd.codegen.decorators.data.AbstractDecorator;
import de.monticore.cd.facade.CDMethodFacade;
import de.monticore.cd.methodtemplates.CD4C;
import de.monticore.cd4code.CD4CodeMill;
import de.monticore.cd4code._visitor.CD4CodeTraverser;
import de.monticore.cd4codebasis._ast.ASTCDInterface;
import de.monticore.cd4codebasis._ast.ASTCDMethod;
import de.monticore.cd4codebasis._ast.ASTCDParameter;
import de.monticore.cdbasis._ast.ASTCDClass;
import de.monticore.cdbasis._ast.ASTCDDefinition;
import de.monticore.cdbasis._visitor.CDBasisVisitor2;
import de.monticore.generating.templateengine.TemplateHookPoint;
import de.monticore.types.MCTypeFacade;
import de.monticore.types.mcbasictypes._ast.ASTMCQualifiedType;
import de.monticore.types.mcbasictypes._ast.ASTMCType;

import java.util.*;

import static de.monticore.cd.codegen.CD2JavaTemplates.EMPTY_BODY;

/**
* Applies the Visitor-Pattern to the CD
*/
public class VisitorDecorator extends AbstractDecorator<AbstractDecorator.NoData> implements
CDBasisVisitor2 {

protected static final String SUFFIX = "Visitor";

@Override
@SuppressWarnings("rawtypes")
public Iterable<Class<? extends IDecorator>> getMustRunAfter() {
//We check that the SetterDecorator has added a Getter for an attribute,
// thus the Getter decorator has to run before.
return Iterables.concat(super.getMustRunAfter(), List.of(GetterDecorator.class));
}

@Override
public void visit(ASTCDDefinition clazz) {
if (decoratorData.shouldDecorate(this.getClass(), clazz)) {
// Get the parent (package or CDDef)
ASTNode origParent = this.decoratorData.getParent(clazz).get();
ASTNode decParent = this.decoratorData.getAsDecorated(origParent);

// create a Visitor interface for the class
ASTCDInterface interfaceVisitorArtifact = CD4CodeMill.cDInterfaceBuilder().setName("I" + clazz
.getName() + SUFFIX).setModifier(CD4CodeMill.modifierBuilder().PUBLIC().build()).build();

addElementToParent(decParent, interfaceVisitorArtifact);

visitorInterfaceStack.push(interfaceVisitorArtifact);

}
}

@Override
public void endVisit(ASTCDDefinition clazz) {
if (decoratorData.shouldDecorate(this.getClass(), clazz)) {
visitorInterfaceStack.pop();
}
}

@Override
public void visit(ASTCDClass clazz) {
if (decoratorData.shouldDecorate(this.getClass(), clazz)) {
ASTCDClass decClazz = decoratorData.getAsDecorated(clazz);
String packageName = clazz.getSymbol().getPackageName();

String visitorInterfaceName = packageName.isEmpty() ? visitorInterfaceStack.peek().getName()
: packageName + "." + visitorInterfaceStack.peek().getName();

ASTMCQualifiedType visitorInterfaceQualifiedType = MCTypeFacade.getInstance()
.createQualifiedType(visitorInterfaceName);
ASTCDParameter visitorParameter = CD4CodeMill.cDParameterBuilder().setName("visitor")
.setMCType(visitorInterfaceQualifiedType).build();
//create a type of the class
ASTMCType classType = MCTypeFacade.getInstance().createQualifiedType(clazz.getName());
ASTCDParameter classParameter = CD4CodeMill.cDParameterBuilder().setName("node").setMCType(
classType).build();

// construct visitor handling methods
ASTCDMethod acceptMethod = CDMethodFacade.getInstance().createMethod(CD4CodeMill
.modifierBuilder().PUBLIC().build(), "accept", visitorParameter);

// add the interface methods to the pojo class
addToClass(decClazz, acceptMethod);
glexOpt.ifPresent(glex -> glex.replaceTemplate(EMPTY_BODY, acceptMethod,
new TemplateHookPoint("methods.visitor.Accept", clazz.getName())));
// new StringHookPoint("visitor.visit ((" + clazz.getName() + ")this);")));

CD4C.getInstance().addImport(decClazz, visitorInterfaceName);
this.decParent.push(decClazz);

// add visit method
ASTCDMethod visitMethod = CDMethodFacade.getInstance().createMethod(CD4CodeMill
.modifierBuilder().PUBLIC().ABSTRACT().build(), "visit", classParameter);
visitorInterfaceStack.peek().addCDMember(visitMethod);
}
}

@Override
public void endVisit(ASTCDClass clazz) {
if (decoratorData.shouldDecorate(this.getClass(), clazz)) {
decParent.pop();
}
}

protected Stack<ASTCDInterface> visitorInterfaceStack = new Stack<>();
protected Stack<ASTCDClass> decParent = new Stack<>();

@Override
public void addToTraverser(CD4CodeTraverser traverser) {
traverser.add4CDBasis(this);
}

}
Loading
Loading