Skip to content
Snippets Groups Projects
Commit 56be33c4 authored by Johannes Mey's avatar Johannes Mey
Browse files

Merge branch '19-poc-use-mustache-as-template-engine' into 'master'

Resolve "PoC: Use mustache as template engine"

Closes #19

See merge request jastadd/ros2rag!2
parents 52785f37 4c7463c6
No related branches found
No related tags found
No related merge requests found
Showing
with 403 additions and 251 deletions
...@@ -17,10 +17,9 @@ buildscript { ...@@ -17,10 +17,9 @@ buildscript {
} }
dependencies { dependencies {
implementation 'com.fasterxml.jackson.core:jackson-core:2.9.8' implementation group: 'com.github.spullara.mustache.java', name: 'compiler', version: '0.9.6'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.9.8' implementation group: 'org.apache.logging.log4j', name: 'log4j-jul', version: '2.11.2'
// api 'org.jastadd:jastadd:2.3.4' runtime group: 'org.jastadd', name: 'jastadd', version: '2.3.4'
runtime 'org.jastadd:jastadd:2.3.4'
api group: 'net.sf.beaver', name: 'beaver-rt', version: '0.9.11' api group: 'net.sf.beaver', name: 'beaver-rt', version: '0.9.11'
} }
...@@ -62,6 +61,7 @@ task relast(type: JavaExec) { ...@@ -62,6 +61,7 @@ task relast(type: JavaExec) {
"../libs/relast.jar", "../libs/relast.jar",
"../relast.preprocessor/src/main/jastadd/RelAst.relast", "../relast.preprocessor/src/main/jastadd/RelAst.relast",
"./src/main/jastadd/Ros2Rag.relast", "./src/main/jastadd/Ros2Rag.relast",
"./src/main/jastadd/MustacheNodes.relast",
"--listClass=java.util.ArrayList", "--listClass=java.util.ArrayList",
"--jastAddList=JastAddList", "--jastAddList=JastAddList",
"--useJastAddNames", "--useJastAddNames",
...@@ -72,11 +72,12 @@ task relast(type: JavaExec) { ...@@ -72,11 +72,12 @@ task relast(type: JavaExec) {
inputs.files file("../libs/relast.jar"), inputs.files file("../libs/relast.jar"),
file("../relast.preprocessor/src/main/jastadd/RelAST.relast"), file("../relast.preprocessor/src/main/jastadd/RelAST.relast"),
file("src/main/jastadd/Ros2Rag.relast") file("./src/main/jastadd/Ros2Rag.relast")
file("./src/main/jastadd/MustacheNodes.relast")
outputs.files file("./src/gen/jastadd/Ros2Rag.ast"), outputs.files file("./src/gen/jastadd/Ros2Rag.ast"),
file("src/gen/jastadd/Ros2Rag.jadd"), file("./src/gen/jastadd/Ros2Rag.jadd"),
file("src/gen/jastadd/Ros2RagRefResolver.jadd"), file("./src/gen/jastadd/Ros2RagRefResolver.jadd"),
file('src/gen/jastadd/Ros2RagResolverStubs.jrag') file('./src/gen/jastadd/Ros2RagResolverStubs.jrag')
} }
jastadd { jastadd {
......
//TypeComponentMustache ;
//rel TypeComponentMustache.TypeComponent -> TypeComponent ;
MRos2Rag ::= ReadDefinition:MReadDefinition* WriteDefinition:MWriteDefinition* MappingDefinition:MMappingDefinition* DependencyDefinition:MDependencyDefinition* RootTypeComponent:MTypeComponent* TokenComponent:MTokenComponent*;
abstract MUpdateDefinition ::= InnerMappingDefinition:MInnerMappingDefinition*;
MReadDefinition : MUpdateDefinition;
MWriteDefinition : MUpdateDefinition;
MMappingDefinition;
MInnerMappingDefinition;
MDependencyDefinition;
MTypeComponent;
MTokenComponent;
rel MRos2Rag.Ros2Rag -> Ros2Rag;
rel MInnerMappingDefinition.MappingDefinition -> MappingDefinition;
rel MReadDefinition.ReadFromMqttDefinition -> ReadFromMqttDefinition;
rel MWriteDefinition.WriteToMqttDefinition -> WriteToMqttDefinition;
rel MMappingDefinition.MappingDefinition -> MappingDefinition;
rel MDependencyDefinition.DependencyDefinition -> DependencyDefinition;
rel MTypeComponent.TypeComponent -> TypeComponent;
rel MTokenComponent.TokenComponent -> TokenComponent;
rel MTokenComponent.DependencyDefinition* -> MDependencyDefinition;
...@@ -2,10 +2,12 @@ aspect Navigation { ...@@ -2,10 +2,12 @@ aspect Navigation {
// --- program --- // --- program ---
eq Ros2Rag.getChild().program() = getProgram(); eq Ros2Rag.getChild().program() = getProgram();
eq MRos2Rag.getChild().program() = getRos2Rag().program();
// --- ros2rag // --- ros2rag ---
inh Ros2Rag ASTNode.ros2rag(); inh Ros2Rag ASTNode.ros2rag();
eq Ros2Rag.getChild().ros2rag() = this; eq Ros2Rag.getChild().ros2rag() = this;
eq MRos2Rag.getChild().ros2rag() = getRos2Rag();
// --- containedFile (first equation should be in preprocessor) --- // --- containedFile (first equation should be in preprocessor) ---
eq Program.getChild().containedFile() = null; eq Program.getChild().containedFile() = null;
...@@ -32,6 +34,7 @@ aspect Navigation { ...@@ -32,6 +34,7 @@ aspect Navigation {
eq GrammarFile.getChild().containedFileName() = getFileName(); eq GrammarFile.getChild().containedFileName() = getFileName();
eq Ros2Rag.getChild().containedFileName() = getFileName(); eq Ros2Rag.getChild().containedFileName() = getFileName();
eq Program.getChild().containedFileName() = null; eq Program.getChild().containedFileName() = null;
eq MRos2Rag.getChild().containedFileName() = null;
// --- isTokenUpdateDefinition --- // --- isTokenUpdateDefinition ---
syn boolean UpdateDefinition.isTokenUpdateDefinition() = false; syn boolean UpdateDefinition.isTokenUpdateDefinition() = false;
...@@ -49,6 +52,10 @@ aspect Navigation { ...@@ -49,6 +52,10 @@ aspect Navigation {
syn WriteToMqttDefinition UpdateDefinition.asWriteToMqttDefinition() = null; syn WriteToMqttDefinition UpdateDefinition.asWriteToMqttDefinition() = null;
eq WriteToMqttDefinition.asWriteToMqttDefinition() = this; eq WriteToMqttDefinition.asWriteToMqttDefinition() = this;
// --- asReadFromMqttDefinition ---
syn ReadFromMqttDefinition UpdateDefinition.asReadFromMqttDefinition() = null;
eq ReadFromMqttDefinition.asReadFromMqttDefinition() = this;
// --- targetUpdateDefinition --- // --- targetUpdateDefinition ---
syn WriteToMqttDefinition DependencyDefinition.targetUpdateDefinition() { syn WriteToMqttDefinition DependencyDefinition.targetUpdateDefinition() {
// resolve definition in here, as we do not need resolveMethod in any other place (yet) // resolve definition in here, as we do not need resolveMethod in any other place (yet)
......
...@@ -10,7 +10,6 @@ rel TokenUpdateDefinition.Token -> TokenComponent; ...@@ -10,7 +10,6 @@ rel TokenUpdateDefinition.Token -> TokenComponent;
ReadFromMqttDefinition : TokenUpdateDefinition; ReadFromMqttDefinition : TokenUpdateDefinition;
WriteToMqttDefinition : TokenUpdateDefinition; WriteToMqttDefinition : TokenUpdateDefinition;
// example: RobotArm._AppropriateSpeed canDependOn Joint.CurrentPosition as dependency1
DependencyDefinition ::= <ID>; DependencyDefinition ::= <ID>;
rel DependencyDefinition.Source <-> TokenComponent.DependencySourceDefinition*; rel DependencyDefinition.Source <-> TokenComponent.DependencySourceDefinition*;
rel DependencyDefinition.Target -> TokenComponent; rel DependencyDefinition.Target -> TokenComponent;
......
aspect Configuration { aspect Configuration {
public static boolean ASTNode.loggingEnabledForReads = false; public static boolean ASTNode.loggingEnabledForReads = false;
public static boolean ASTNode.loggingEnabledForWrites = false; public static boolean ASTNode.loggingEnabledForWrites = false;
public static TypeDecl ASTNode.rootNode;
} }
...@@ -21,11 +21,188 @@ aspect GenerationUtils { ...@@ -21,11 +21,188 @@ aspect GenerationUtils {
} }
} }
/* Open questions
- Should all string constants be defined on the normal AST, or on the special mustache AST?
*/
aspect AttributesForMustache {
// --- MRos2Rag ---
eq MRos2Rag.getChild().mqttUpdaterAttribute() = mqttUpdaterAttribute();
eq MRos2Rag.getChild().mqttUpdaterField() = mqttUpdaterField();
syn String MRos2Rag.mqttUpdaterAttribute() = getRos2Rag().mqttUpdaterAttribute();
syn String MRos2Rag.mqttUpdaterField() = getRos2Rag().mqttUpdaterField();
syn String MRos2Rag.mqttSetHostMethod() = getRos2Rag().mqttSetHostMethod();
syn String MRos2Rag.mqttWaitUntilReadyMethod() = getRos2Rag().mqttWaitUntilReadyMethod();
syn String MRos2Rag.mqttCloseMethod() = getRos2Rag().mqttCloseMethod();
// --- MUpdateDefinition ---
syn String MUpdateDefinition.preemptiveExpectedValue();
syn String MUpdateDefinition.preemptiveReturn();
syn TokenUpdateDefinition MUpdateDefinition.updateDef();
syn String MUpdateDefinition.firstInputVarName();
eq MUpdateDefinition.getInnerMappingDefinition(int i).isLast() = i == getNumInnerMappingDefinition() - 1;
eq MUpdateDefinition.getInnerMappingDefinition().resultVarPrefix() = resultVarPrefix();
eq MUpdateDefinition.getInnerMappingDefinition(int i).inputVarName() = i == 0 ? firstInputVarName() : resultVarPrefix() + getInnerMappingDefinition(i - 1).getMappingDefinition().methodName();
inh String MUpdateDefinition.mqttUpdaterAttribute();
syn String MUpdateDefinition.connectMethod() = updateDef().connectMethod();
syn TokenComponent MUpdateDefinition.token() = updateDef().getToken();
syn boolean MUpdateDefinition.alwaysApply() = updateDef().getAlwaysApply();
syn String MUpdateDefinition.resultVarPrefix() = "result"; // we do not need "_" here, because methodName begins with one
syn String MUpdateDefinition.parentTypeName() = token().containingTypeDecl().getName();
syn String MUpdateDefinition.tokenName() = token().getName();
syn MInnerMappingDefinition MUpdateDefinition.lastDefinition() = getInnerMappingDefinition(getNumInnerMappingDefinition() - 1);
syn String MUpdateDefinition.lastDefinitionToType() = lastDefinition().ToType();
syn String MUpdateDefinition.lastDefinitionName() = lastDefinition().methodName();
syn String MUpdateDefinition.lastResult() = resultVarPrefix() + lastDefinitionName();
syn String MUpdateDefinition.condition() {
if (lastDefinition().getMappingDefinition().getToType().isArray()) {
return "java.util.Arrays.equals(" + preemptiveExpectedValue() + ", " + lastResult() + ")";
}
if (token().isPrimitiveType() && lastDefinition().getMappingDefinition().getToType().isPrimitiveType()) {
return preemptiveExpectedValue() + " == " + lastResult();
}
if (lastDefinition().getMappingDefinition().isDefaultMappingDefinition()) {
return preemptiveExpectedValue() + " != null && " + preemptiveExpectedValue() + ".equals(" + lastResult() + ")";
}
return preemptiveExpectedValue() + " != null ? " + preemptiveExpectedValue() + ".equals(" + lastResult() + ") : " + lastResult() + " == null";
}
// --- MInnerMappingDefinition ---
inh boolean MInnerMappingDefinition.isLast();
inh String MInnerMappingDefinition.resultVarPrefix();
syn String MInnerMappingDefinition.ToType() = getMappingDefinition().getToType().prettyPrint();
syn String MInnerMappingDefinition.methodName() = getMappingDefinition().methodName();
inh String MInnerMappingDefinition.inputVarName();
// --- MReadDefinition ---
eq MReadDefinition.preemptiveExpectedValue() = "get" + tokenName() + "()";
eq MReadDefinition.preemptiveReturn() = "return;";
eq MReadDefinition.updateDef() = getReadFromMqttDefinition();
eq MReadDefinition.firstInputVarName() = "message";
// --- MWriteDefinition ---
eq MWriteDefinition.preemptiveExpectedValue() = lastValue();
eq MWriteDefinition.preemptiveReturn() = "return false;";
eq MWriteDefinition.updateDef() = getWriteToMqttDefinition();
eq MWriteDefinition.firstInputVarName() = "get" + tokenName() + "()";
syn String MWriteDefinition.writeTopic() = getWriteToMqttDefinition().writeTopic();
syn String MWriteDefinition.lastValue() = getWriteToMqttDefinition().lastValue();
syn String MWriteDefinition.updateMethod() = getWriteToMqttDefinition().updateMethod();
syn String MWriteDefinition.writeMethod() = getWriteToMqttDefinition().writeMethod();
syn String MWriteDefinition.tokenResetMethod() = getWriteToMqttDefinition().tokenResetMethod();
// --- MMappingDefinition ---
syn String MMappingDefinition.toType() = getMappingDefinition().getToType().prettyPrint();
syn String MMappingDefinition.methodName() = getMappingDefinition().methodName();
syn String MMappingDefinition.fromType() = getMappingDefinition().getFromType().prettyPrint();
syn String MMappingDefinition.fromVariableName() = getMappingDefinition().getFromVariableName();
syn String MMappingDefinition.content() = getMappingDefinition().getContent();
// --- MDependencyDefinition ---
syn String MDependencyDefinition.targetParentTypeName() = getDependencyDefinition().getTarget().containingTypeDecl().getName();
syn String MDependencyDefinition.dependencyMethod() = getDependencyDefinition().dependencyMethod();
syn String MDependencyDefinition.sourceParentTypeName() = getDependencyDefinition().getSource().containingTypeDecl().getName();
syn String MDependencyDefinition.internalRelationPrefix() = getDependencyDefinition().internalRelationPrefix();
syn nta MUpdateDefinition MDependencyDefinition.targetUpdateDefinition() {
return getDependencyDefinition().targetUpdateDefinition().toMustache();
}
// --- MTypeComponent ---
syn String MTypeComponent.name() = getTypeComponent().getName();
inh String MTypeComponent.mqttUpdaterAttribute();
inh String MTypeComponent.mqttUpdaterField();
// --- MTokenComponent ---
syn String MTokenComponent.parentTypeName() = getTokenComponent().containingTypeDecl().getName();
syn String MTokenComponent.name() = getTokenComponent().getName();
syn String MTokenComponent.javaType() = getTokenComponent().getJavaTypeUse().prettyPrint();
syn String MTokenComponent.internalName() = getTokenComponent().internalName();
// --- toMustache ---
syn lazy MRos2Rag Ros2Rag.toMustache() {
MRos2Rag result = new MRos2Rag();
result.setRos2Rag(this);
for (UpdateDefinition def : getUpdateDefinitionList()) {
if (def.isWriteToMqttDefinition()) {
result.addWriteDefinition(def.asWriteToMqttDefinition().toMustache());
} else {
result.addReadDefinition(def.asReadFromMqttDefinition().toMustache());
}
}
for (MappingDefinition def : allMappingDefinitions()) {
result.addMappingDefinition(def.toMustache());
}
for (DependencyDefinition def : getDependencyDefinitionList()) {
result.addDependencyDefinition(def.toMustache());
}
for (TokenComponent token : getProgram().allTokenComponents()) {
if (!token.getDependencySourceDefinitionList().isEmpty()) {
result.addTokenComponent(token.toMustache());
}
}
for (Component child : rootNode.getComponentList()) {
if (child.isTypeComponent()) {
result.addRootTypeComponent(child.asTypeComponent().toMustache());
}
}
return result;
}
//MInnerMappingDefinition.MappingDefinition -> MappingDefinition;
protected void MUpdateDefinition.addInnerMappings() {
for (MappingDefinition def : updateDef().effectiveMappings()) {
MInnerMappingDefinition inner = new MInnerMappingDefinition();
inner.setMappingDefinition(def);
addInnerMappingDefinition(inner);
}
}
syn lazy MReadDefinition ReadFromMqttDefinition.toMustache() {
MReadDefinition result = new MReadDefinition();
result.setReadFromMqttDefinition(this);
result.addInnerMappings();
return result;
}
syn lazy MWriteDefinition WriteToMqttDefinition.toMustache() {
MWriteDefinition result = new MWriteDefinition();
result.setWriteToMqttDefinition(this);
result.addInnerMappings();
return result;
}
syn lazy MMappingDefinition MappingDefinition.toMustache() {
MMappingDefinition result = new MMappingDefinition();
result.setMappingDefinition(this);
return result;
}
syn lazy MDependencyDefinition DependencyDefinition.toMustache() {
MDependencyDefinition result = new MDependencyDefinition();
result.setDependencyDefinition(this);
return result;
}
syn lazy MTypeComponent TypeComponent.toMustache() {
MTypeComponent result = new MTypeComponent();
result.setTypeComponent(this);
return result;
}
syn lazy MTokenComponent TokenComponent.toMustache() {
MTokenComponent result = new MTokenComponent();
result.setTokenComponent(this);
for (DependencyDefinition def : getDependencySourceDefinitionList()) {
result.addDependencyDefinition(def.toMustache());
}
return result;
}
}
aspect AspectGeneration { aspect AspectGeneration {
// naming convention attributes
syn String TokenComponent.internalName() = getDependencySourceDefinitionList().isEmpty() ? externalName() : "_internal_" + getName(); syn String TokenComponent.internalName() = getDependencySourceDefinitionList().isEmpty() ? externalName() : "_internal_" + getName();
syn String TokenComponent.externalName() = getName(); syn String TokenComponent.externalName() = getName();
// naming convention attributes
syn String TokenUpdateDefinition.connectMethod() = "connect" + getToken().getName(); syn String TokenUpdateDefinition.connectMethod() = "connect" + getToken().getName();
syn String WriteToMqttDefinition.writeTopic() = "_topic_" + getToken().getName(); syn String WriteToMqttDefinition.writeTopic() = "_topic_" + getToken().getName();
syn String WriteToMqttDefinition.lastValue() = "_lastValue" + getToken().getName(); syn String WriteToMqttDefinition.lastValue() = "_lastValue" + getToken().getName();
...@@ -39,10 +216,6 @@ aspect AspectGeneration { ...@@ -39,10 +216,6 @@ aspect AspectGeneration {
syn String DependencyDefinition.internalRelationPrefix() = "_internal_" + getID(); syn String DependencyDefinition.internalRelationPrefix() = "_internal_" + getID();
syn String DependencyDefinition.internalTokenName() = getSource().internalName(); syn String DependencyDefinition.internalTokenName() = getSource().internalName();
inh String UpdateDefinition.mqttUpdaterAttribute();
inh String MappingDefinition.mqttUpdaterAttribute();
inh String DependencyDefinition.mqttUpdaterAttribute();
eq Ros2Rag.getChild().mqttUpdaterAttribute() = mqttUpdaterAttribute();
syn String Ros2Rag.mqttUpdaterAttribute() = "_mqttUpdater"; syn String Ros2Rag.mqttUpdaterAttribute() = "_mqttUpdater";
syn String Ros2Rag.mqttUpdaterField() = "_mqttUpdater"; syn String Ros2Rag.mqttUpdaterField() = "_mqttUpdater";
...@@ -50,247 +223,43 @@ aspect AspectGeneration { ...@@ -50,247 +223,43 @@ aspect AspectGeneration {
syn String Ros2Rag.mqttWaitUntilReadyMethod() = "MqttWaitUntilReady"; syn String Ros2Rag.mqttWaitUntilReadyMethod() = "MqttWaitUntilReady";
syn String Ros2Rag.mqttCloseMethod() = "MqttCloseConnections"; syn String Ros2Rag.mqttCloseMethod() = "MqttCloseConnections";
public String Ros2Rag.generateAspect(String rootNodeName) { // naming copy attributes
StringBuilder sb = new StringBuilder(); // --- mqttUpdaterAttribute ---
TypeDecl rootNode = getProgram().resolveTypeDecl(rootNodeName); inh String UpdateDefinition.mqttUpdaterAttribute();
generateMqttAspect(sb, rootNode); inh String MappingDefinition.mqttUpdaterAttribute();
generateGrammarExtension(sb); inh String DependencyDefinition.mqttUpdaterAttribute();
return sb.toString(); eq Ros2Rag.getChild().mqttUpdaterAttribute() = mqttUpdaterAttribute();
}
public void Ros2Rag.generateMqttAspect(StringBuilder sb, TypeDecl rootNode) {
String rootNodeName = rootNode.getName();
sb.append("aspect MQTT {\n");
sb.append(ind(1)).append("private MqttUpdater ").append(rootNodeName)
.append(".").append(mqttUpdaterField()).append(" = new MqttUpdater();\n");
// mqttSetHost(String host)
sb.append(ind(1)).append("public void ").append(rootNodeName).append(".")
.append(mqttSetHostMethod()).append("(String host) throws java.io.IOException {\n");
sb.append(ind(2)).append(mqttUpdaterField()).append(".setHost(host);\n");
sb.append(ind(1)).append("}\n");
// mqttSetHost(String host, int port)
sb.append(ind(1)).append("public void ").append(rootNodeName).append(".")
.append(mqttSetHostMethod()).append("(String host, int port) throws java.io.IOException {\n");
sb.append(ind(2)).append(mqttUpdaterField()).append(".setHost(host, port);\n");
sb.append(ind(1)).append("}\n\n");
// mqttWaitUntilReady
sb.append(ind(1)).append("public boolean ").append(rootNodeName).append(".")
.append(mqttWaitUntilReadyMethod()).append("(long time, java.util.concurrent.TimeUnit unit) {\n");
sb.append(ind(2)).append("return ").append(mqttUpdaterField()).append(".waitUntilReady(time, unit);\n");
sb.append(ind(1)).append("}\n\n");
// mqttClose
sb.append(ind(1)).append("public void ").append(rootNodeName).append(".")
.append(mqttCloseMethod()).append("() {\n");
sb.append(ind(2)).append(mqttUpdaterField()).append(".close();\n");
sb.append(ind(1)).append("}\n\n");
// mqttUpdater
sb.append(ind(1)).append("inh MqttUpdater ASTNode.").append(mqttUpdaterAttribute()).append("();\n");
for (Component child : rootNode.getComponentList()) {
if (child.isTypeComponent()) {
sb.append(ind(1)).append("eq ").append(rootNodeName)
.append(".get").append(child.getName()).append("().")
.append(mqttUpdaterAttribute()).append("() = ").append(mqttUpdaterField()).append(";\n");
}
}
sb.append("}\n\n");
}
public void Ros2Rag.generateGrammarExtension(StringBuilder sb) {
sb.append("aspect ROS2RAG {\n");
for (UpdateDefinition def : getUpdateDefinitionList()) {
def.generateAspect(sb);
}
for (MappingDefinition def : allMappingDefinitions()) {
def.generateAspect(sb);
}
for (DependencyDefinition def : getDependencyDefinitionList()) {
def.generateAspect(sb);
}
for (TokenComponent token : getProgram().allTokenComponents()) {
token.generateAspect(sb);
}
sb.append("}\n");
}
abstract void UpdateDefinition.generateAspect(StringBuilder sb); // --- rootNodeName ---
syn String ASTNode.rootNodeName() = rootNode.getName();
String TokenUpdateDefinition.generateMappingApplication(StringBuilder sb, int indent, public String Ros2Rag.generateAspect(String rootNodeName) {
String initialInputVariableName) { rootNode = getProgram().resolveTypeDecl(rootNodeName);
final String resultVariablePrefix = "result"; // we do not need "_" here, because methodName begins with one return toMustache().generateAspect();
String inputVariableName = initialInputVariableName;
// last variable need to be declared before begin of try
MappingDefinition lastDefinition = effectiveMappings().get(effectiveMappings().size() - 1);
sb.append(ind(indent)).append(lastDefinition.getToType().prettyPrint()).append(" ")
.append(resultVariablePrefix).append(lastDefinition.methodName()).append(";\n");
sb.append(ind(indent)).append("try {\n");
for (MappingDefinition mappingDefinition : effectiveMappings()) {
String resultVariableName = resultVariablePrefix + mappingDefinition.methodName();
sb.append(ind(indent + 1));
if (mappingDefinition != lastDefinition) {
sb.append(mappingDefinition.getToType().prettyPrint()).append(" ");
}
sb.append(resultVariablePrefix).append(mappingDefinition.methodName())
.append(" = ").append(mappingDefinition.methodName()).append("(")
.append(inputVariableName).append(");\n");
inputVariableName = resultVariableName;
}
sb.append(ind(indent)).append("} catch (Exception e) {\n");
sb.append(ind(indent + 1)).append("e.printStackTrace();\n");
sb.append(ind(indent + 1)).append(preemptiveReturnStatement()).append("\n");
sb.append(ind(indent)).append("}\n");
if (!getAlwaysApply()) {
MappingDefinition lastMapping = effectiveMappings().get(effectiveMappings().size() - 1);
sb.append(ind(indent)).append("if (");
if (lastMapping.getToType().isArray()) {
sb.append("java.util.Arrays.equals(").append(preemptiveExpectedValue())
.append(", ").append(inputVariableName).append(")");
} else {
sb.append(preemptiveExpectedValue());
if (getToken().isPrimitiveType() && lastMapping.getToType().isPrimitiveType()) {
sb.append(" == ").append(inputVariableName);
} else if (lastMapping.isDefaultMappingDefinition()) {
sb.append(" != null && ").append(preemptiveExpectedValue()).append(".equals(")
.append(inputVariableName).append(")");
} else {
sb.append(" != null ? ").append(preemptiveExpectedValue()).append(".equals(")
.append(inputVariableName).append(")").append(" : ")
.append(inputVariableName).append(" == null");
}
}
sb.append(") { ").append(preemptiveReturnStatement()).append(" }\n");
}
return inputVariableName;
} }
syn String TokenUpdateDefinition.preemptiveExpectedValue(); public String MRos2Rag.generateAspect() {
eq ReadFromMqttDefinition.preemptiveExpectedValue() = "get" + getToken().getName() + "()"; StringBuilder sb = new StringBuilder();
eq WriteToMqttDefinition.preemptiveExpectedValue() = lastValue(); com.github.mustachejava.reflect.ReflectionObjectHandler roh = new com.github.mustachejava.reflect.ReflectionObjectHandler() {
syn String TokenUpdateDefinition.preemptiveReturnStatement();
eq ReadFromMqttDefinition.preemptiveReturnStatement() = "return;";
eq WriteToMqttDefinition.preemptiveReturnStatement() = "return false;";
@Override @Override
void ReadFromMqttDefinition.generateAspect(StringBuilder sb) { public com.github.mustachejava.Binding createBinding(String name, final com.github.mustachejava.TemplateContext tc, com.github.mustachejava.Code code) {
sb.append(ind(1)).append("public void ").append(getToken().containingTypeDecl().getName()).append(".") return new com.github.mustachejava.reflect.GuardedBinding(this, name, tc, code) {
.append(connectMethod()).append("(String topic) {\n");
sb.append(ind(2)).append(mqttUpdaterAttribute()).append("().newConnection(topic, message -> {\n");
String lastResult = generateMappingApplication(sb, 3, "message");
if (loggingEnabledForReads) {
sb.append(ind(3)).append("System.out.println(\"[Read] \" + topic + \" -> ")
.append(getToken().getName()).append(" = \" + ").append(lastResult)
.append(");\n");
}
sb.append(ind(3)).append("set").append(getToken().getName()).append("(").append(lastResult).append(");\n");
sb.append(ind(2)).append("});\n");
sb.append(ind(1)).append("}\n\n");
}
@Override @Override
void WriteToMqttDefinition.generateAspect(StringBuilder sb) { protected synchronized com.github.mustachejava.util.Wrapper getWrapper(String name, java.util.List<Object> scopes) {
String parentTypeName = getToken().containingTypeDecl().getName(); com.github.mustachejava.util.Wrapper wrapper = super.getWrapper(name, scopes);
// fields if (wrapper instanceof com.github.mustachejava.reflect.MissingWrapper) {
sb.append(ind(1)).append("private String ").append(parentTypeName).append(".") throw new com.github.mustachejava.MustacheException(name + " not found in " + tc);
.append(writeTopic()).append(" = null;\n");
sb.append(ind(1)).append("private byte[] ").append(parentTypeName).append(".")
.append(lastValue()).append(" = null;\n");
// connect method
sb.append(ind(1)).append("public void ").append(parentTypeName).append(".")
.append(connectMethod()).append("(String topic, boolean writeCurrentValue) {\n");
sb.append(ind(2)).append(writeTopic()).append(" = topic;\n");
sb.append(ind(2)).append(updateMethod()).append("();\n");
sb.append(ind(2)).append("if (writeCurrentValue) {\n");
sb.append(ind(3)).append(writeMethod()).append("();\n");
sb.append(ind(2)).append("}\n");
sb.append(ind(1)).append("}\n\n");
// update method
sb.append(ind(1)).append("protected boolean ").append(parentTypeName).append(".")
.append(updateMethod()).append("() {\n");
sb.append(ind(2)).append(tokenResetMethod()).append("();\n");
String lastResult = generateMappingApplication(sb, 2, "get" + getToken().getName() + "()");
sb.append(ind(2)).append(lastValue()).append(" = ").append(lastResult).append(";\n");
sb.append(ind(2)).append("return true;\n");
sb.append(ind(1)).append("}\n\n");
// write method
sb.append(ind(1)).append("protected void ").append(parentTypeName).append(".")
.append(writeMethod()).append("() {\n");
if (loggingEnabledForWrites) {
sb.append(ind(2)).append("System.out.println(\"[Write] ").append(getToken().getName())
.append(" = \" + ")
.append("get").append(getToken().getName()).append("() + \" -> \" + ")
.append(writeTopic()).append(");\n");
}
// _mqttUpdater().publish(${writeTopic()}, ${lastValue()});
sb.append(ind(2)).append(mqttUpdaterAttribute()).append("().publish(")
.append(writeTopic()).append(", ").append(lastValue()).append(");\n");
sb.append(ind(1)).append("}\n\n");
}
void MappingDefinition.generateAspect(StringBuilder sb) {
sb.append(ind(1)).append("protected static ").append(getToType().prettyPrint())
.append(" ASTNode.").append(methodName()).append("(")
.append(getFromType().prettyPrint()).append(" ").append(getFromVariableName())
.append(") throws Exception {\n");
for (String line : getContent().split("\n")) {
if (!line.trim().isEmpty()) {
sb.append(ind(2)).append(line).append("\n");
}
} }
sb.append(ind(1)).append("}\n\n"); return wrapper;
} }
};
void DependencyDefinition.generateAspect(StringBuilder sb) {
String targetParentTypeName = getTarget().containingTypeDecl().getName();
String sourceParentTypeName = getSource().containingTypeDecl().getName();
// dependency method
sb.append(ind(1)).append("public void ").append(targetParentTypeName).append(".")
.append(dependencyMethod()).append("(").append(sourceParentTypeName).append(" source) {\n");
sb.append(ind(2)).append("add").append(internalRelationPrefix()).append("Source(source);\n");
sb.append(ind(1)).append("}\n\n");
} }
};
void TokenComponent.generateAspect(StringBuilder sb) { com.github.mustachejava.DefaultMustacheFactory mf = new com.github.mustachejava.DefaultMustacheFactory();
if (getDependencySourceDefinitionList().isEmpty()) { return; } mf.setObjectHandler(roh);
com.github.mustachejava.Mustache m = mf.compile("ros2rag.mustache");
String parentTypeName = containingTypeDecl().getName(); m.execute(new java.io.PrintWriter(new org.jastadd.ros2rag.compiler.AppendableWriter(sb)), this);
// virtual setter return sb.toString();
sb.append(ind(1)).append("public ").append(parentTypeName).append(" ")
.append(parentTypeName).append(".set").append(getName()).append("(")
.append(getJavaTypeUse().prettyPrint()).append(" value) {\n");
sb.append(ind(2)).append("set").append(internalName()).append("(value);\n");
for (DependencyDefinition dependencyDefinition : getDependencySourceDefinitionList()) {
String targetParentTypeName = dependencyDefinition.getTarget().containingTypeDecl().getName();
sb.append(ind(2)).append("for (").append(targetParentTypeName).append(" target : get")
.append(dependencyDefinition.internalRelationPrefix()).append("TargetList()) {\n");
sb.append(ind(3)).append("if (target.")
.append(dependencyDefinition.targetUpdateDefinition().updateMethod())
.append("()) {\n");
sb.append(ind(4)).append("target.")
.append(dependencyDefinition.targetUpdateDefinition().writeMethod())
.append("();\n");
sb.append(ind(3)).append("}\n");
sb.append(ind(2)).append("}\n");
}
sb.append(ind(2)).append("return this;\n");
sb.append(ind(1)).append("}\n\n");
// virtual getter
sb.append(ind(1)).append("public ").append(getJavaTypeUse().prettyPrint())
.append(" ").append(parentTypeName).append(".get").append(getName()).append("() {\n");
sb.append(ind(2)).append("return get").append(internalName()).append("();\n");
sb.append(ind(1)).append("}\n\n");
} }
} }
......
package org.jastadd.ros2rag.compiler;
import java.io.IOException;
import java.io.Writer;
/**
* Writer appending to a StringBuilder.
*
* @author rschoene - Initial contribution
*/
public class AppendableWriter extends Writer {
private final StringBuilder sb;
public AppendableWriter(StringBuilder sb) {
this.sb = sb;
}
@Override
public void write(char[] chars, int off, int len) throws IOException {
sb.append(chars, off, len);
}
@Override
public void write(String str) throws IOException {
sb.append(str);
}
@Override
public void flush() {
}
@Override
public void close() {
}
}
...@@ -37,6 +37,8 @@ public class Compiler { ...@@ -37,6 +37,8 @@ public class Compiler {
} }
public void run(String[] args) throws CommandLineException, CompilerException { public void run(String[] args) throws CommandLineException, CompilerException {
System.setProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager");
System.setProperty("mustache.debug", "true");
options = new ArrayList<>(); options = new ArrayList<>();
addOptions(); addOptions();
commandLine = new CommandLine(options); commandLine = new CommandLine(options);
......
public void {{targetParentTypeName}}.{{dependencyMethod}}({{sourceParentTypeName}} source) {
add{{internalRelationPrefix}}Source(source);
}
{{lastDefinitionToType}} {{resultVarPrefix}}{{lastDefinitionName}};
try {
{{#InnerMappingDefinitions}}
{{^last}}{{ToType}} {{/last}}{{resultVarPrefix}}{{methodName}} = {{methodName}}({{inputVarName}});{{!inputVarName has to be computed beforehand}}
{{/InnerMappingDefinitions}}
} catch (Exception e) {
e.printStackTrace();
{{preemptiveReturn}}
}
{{^alwaysApply}}
if ({{{condition}}}) {
{{preemptiveReturn}}
}
{{/alwaysApply}}
protected static {{toType}} ASTNode.{{methodName}}({{fromType}} {{fromVariableName}}) throws Exception {
{{{content}}}{{!maybe print line by line to get better indentation}}
}
aspect MQTT {
private MqttUpdater {{rootNodeName}}.{{mqttUpdaterField}} = new MqttUpdater();
public void {{rootNodeName}}.{{mqttSetHostMethod}}(String host) throws java.io.IOException {
{{mqttUpdaterField}}.setHost(host);
}
public void {{rootNodeName}}.{{mqttSetHostMethod}}(String host, int port) throws java.io.IOException {
{{mqttUpdaterField}}.setHost(host, port);
}
public boolean {{rootNodeName}}.{{mqttWaitUntilReadyMethod}}(long time, java.util.concurrent.TimeUnit unit) {
return {{mqttUpdaterField}}.waitUntilReady(time, unit);
}
public void {{rootNodeName}}.{{mqttCloseMethod}}() {
{{mqttUpdaterField}}.close();
}
inh MqttUpdater ASTNode.{{mqttUpdaterAttribute}}();
{{#getRootTypeComponents}}
eq {{rootNodeName}}.get{{name}}().{{mqttUpdaterAttribute}}() = {{mqttUpdaterField}};
{{/getRootTypeComponents}}
}
public void {{parentTypeName}}.{{connectMethod}}(String topic) {
{{mqttUpdaterAttribute}}().newConnection(topic, message -> {
{{> mappingApplication}}
{{#loggingEnabledForReads}}
System.out.println("[Read] " + topic + " -> {{tokenName}} = " + {{lastResult}});{{!lastResult has to be a new attribute}}
{{/loggingEnabledForReads}}
set{{tokenName}}({{lastResult}});
});
}
{{> mqtt}}
aspect ROS2RAG {
{{#ReadDefinitions}}
{{> readDefinition}}
{{/ReadDefinitions}}
{{#WriteDefinitions}}
{{> writeDefinition}}
{{/WriteDefinitions}}
{{#MappingDefinitions}}
{{> mappingDefinition}}
{{/MappingDefinitions}}
{{#DependencyDefinitions}}
{{> dependencyDefinition}}
{{/DependencyDefinitions}}
{{#TokenComponents}}
{{> tokenComponent}}
{{/TokenComponents}}
}
public {{parentTypeName}} {{parentTypeName}}.set{{name}}({{javaType}} value) {
set{{internalName}}(value);
{{#DependencyDefinitions}}
for ({{targetParentTypeName}} target : get{{internalRelationPrefix}}TargetList()) {
{{#targetUpdateDefinition}}
if (target.{{updateMethod}}()) {
target.{{writeMethod}}();
}
{{/targetUpdateDefinition}}
}
{{/DependencyDefinitions}}
return this;
}
public {{javaType}} {{parentTypeName}}.get{{name}}() {
return get{{internalName}}();
}
private String {{parentTypeName}}.{{writeTopic}} = null;
private byte[] {{parentTypeName}}.{{lastValue}} = null;
public void {{parentTypeName}}.{{connectMethod}}(String topic, boolean writeCurrentValue) {
{{writeTopic}} = topic;
{{updateMethod}}();
if (writeCurrentValue) {
{{writeMethod}}();
}
}
protected boolean {{parentTypeName}}.{{updateMethod}}() {
{{tokenResetMethod}}();
{{> mappingApplication}}
{{lastValue}} = {{lastResult}};
return true;
}
protected void {{parentTypeName}}.{{writeMethod}}() {
{{#loggingEnabledForWrites}}
System.out.println("[Write] {{tokenName}} = " + get{{tokenName}}() + " -> " + {{writeTopic}});
{{/loggingEnabledForWrites}}
{{mqttUpdaterAttribute}}().publish({{writeTopic}}, {{lastValue}});
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment