diff --git a/src/main/jastadd/MustacheNodes.relast b/src/main/jastadd/MustacheNodes.relast index 30277272d713c062307b3679dff7db75b71b91ef..87c4d35cd0883cd40a35b17ebb9eb8ce2ee1bd2a 100644 --- a/src/main/jastadd/MustacheNodes.relast +++ b/src/main/jastadd/MustacheNodes.relast @@ -1,2 +1,19 @@ -TypeComponentMustache ; -rel TypeComponentMustache.TypeComponent -> TypeComponent ; +//TypeComponentMustache ; +//rel TypeComponentMustache.TypeComponent -> TypeComponent ; + +MRos2Rag ::= ReadDefinition:MReadDefinition* WriteDefinition:MWriteDefinition* MappingDefinition:MMappingDefinition* DependencyDefinition:MDependencyDefinition* TypeComponent:MTypeComponent*; +MUpdateDefinition ::= <FirstInputVarName>; +MReadDefinition : MUpdateDefinition; +MWriteDefinition : MUpdateDefinition; +MMappingDefinition; +MDependencyDefinition; +MTypeComponent; + +MUpdateDefinition.InnerMappingDefinition* -> MInnerMappingDefinition; +MInnerMappingDefinition.MappingDefinition -> MappingDefinition; +MReadDefinition.ReadFromMqttDefinition -> ReadFromMqttDefinition; +MWriteDefinition.WriteToMqttDefinition -> WriteToMqttDefinition; +MMappingDefinition.MappingDefinition -> MappingDefinition; +MDependencyDefinition.DependencyDefinition -> DependencyDefinition; +MTypeComponent.TypeComponent -> TypeComponent; +MTypeComponent.DependencyDefinition* -> MDependencyDefinition; diff --git a/src/main/jastadd/Navigation.jrag b/src/main/jastadd/Navigation.jrag index e034804ba6f4151c744e7fb495c17f483be7e685..e181bc92401ef3e8e098685ac6047dba88e46954 100644 --- a/src/main/jastadd/Navigation.jrag +++ b/src/main/jastadd/Navigation.jrag @@ -49,6 +49,10 @@ aspect Navigation { syn WriteToMqttDefinition UpdateDefinition.asWriteToMqttDefinition() = null; eq WriteToMqttDefinition.asWriteToMqttDefinition() = this; + // --- asReadFromMqttDefinition --- + syn ReadFromMqttDefinition UpdateDefinition.asReadFromMqttDefinition() = null; + eq ReadFromMqttDefinition.asReadFromMqttDefinition() = this; + // --- targetUpdateDefinition --- syn WriteToMqttDefinition DependencyDefinition.targetUpdateDefinition() { // resolve definition in here, as we do not need resolveMethod in any other place (yet) diff --git a/src/main/jastadd/backend/Generation.jadd b/src/main/jastadd/backend/Generation.jadd index abce6a07b80fb96313de4760511c5339e9da92a0..2f2ff547924d3464c170cd995e6b10ddffeba3e2 100644 --- a/src/main/jastadd/backend/Generation.jadd +++ b/src/main/jastadd/backend/Generation.jadd @@ -21,6 +21,154 @@ aspect GenerationUtils { } } +/* Open questions +- Should all string constants be defined on the normal AST, or on the special mustache AST? +*/ + +aspect AttributesForMustache { + // --- MRos2Rag --- + + // --- MUpdateDefinition --- + syn String MUpdateDefinition.preemptiveExpectedValue(); + syn String MUpdateDefinition.preemptiveReturn(); + syn String MUpdateDefinition.mqttUpdaterAttribute(); + syn UpdateDefinition MUpdateDefinition.updateDef(); + + eq MUpdateDefinition.getMInnerMappingDefinition(int i).isLast() = i == numInnerMappingDefinition(); + eq MUpdateDefinition.getInnerMappingDefinition().resultVarPrefix() = resultVarPrefix(); + eq MUpdateDefinition.getInnerMappingDefinition(int i).inputVarName() = i == 0 ? getFirstInputVarName() : resultVarPrefix() + getMInnerMappingDefinition(i - 1).getMappingDefinition().methodName(); + + 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(numInnerMappingDefinition() - 1); + syn String MUpdateDefinition.lastDefinitionType() = lastDefinition().ToType(); + syn String MUpdateDefinition.lastDefinitionName() = lastDefinition().methodName(); + syn String MUpdateDefinition.condition() { + String lastVarName = resultVarPrefix() + lastDefinitionDefinitionName(); + if (lastDefinition().getMappingDefinition().getToType().isArray()) { + return "java.util.Arrays.equals(" + preemptiveExpectedValue() + ", " + lastVarName + ")"; + } + if (token().isPrimitiveType() && lastDefinition().getMappingDefinition().getToType().isPrimitiveType()) { + return preemptiveExpectedValue() + " == " + lastVarName; + } + if (lastDefinition().getMappingDefinition().isDefaultMappingDefinition()) { + return preemptiveExpectedValue() + " != null && " + preemptiveExpectedValue() + ".equals(" + lastVarName ")"; + } + return preemptiveExpectedValue() + " != null ? " + preemptiveExpectedValue() + ".equals(" + lastVarName ") : " + inputVariableName + " == 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.connectMethod() = getReadFromMqttDefinition().connectMethod(); + eq MReadDefinition.preemptiveExpectedValue() = "get" + TokenName() + "()"; + eq MReadDefinition.preemptiveReturn() = "return;"; + eq MReadDefinition.updateDef() = getReadFromMqttDefinition(); + + syn String MReadDefinition.mqttUpdaterAttribute() = getReadFromMqttDefinition().mqttUpdaterAttribute; + syn String MReadDefinition.lastResult() = getReadFromMqttDefinition(); + + // --- MWriteDefinition --- + eq MWriteDefinition.preemptiveExpectedValue() = lastValue(); + eq MWriteDefinition.preemptiveReturn() = "return false;"; + eq MWriteDefinition.updateDef() = getWriteToMqttDefinition(); + + 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 wrap(getDependencyDefinition().targetUpdateDefinition()); + } + + // --- MTypeComponent --- + syn String MTypeComponent.parentTypeName() = getTypeComponent().containingTypeDecl().getName(); + syn String MTypeComponent.name() = getTypeComponent().getName(); + syn String MTypeComponent.javaType() = getTypeComponent().getJavaTypeUse().prettyPrint(); + syn String MTypeComponent.internalName() = getTypeComponent().internalName(); + + // --- wrap --- + syn lazy MRos2Rag Ros2Rag.wrap() { + MRos2Rag result = new MRos2Rag(); + for (UpdateDefinition def : getUpdateDefinitionList()) { + if (def.isWriteToMqttDefinition()) { + result.addWriteDefinition(def.asWriteToMqttDefinition.wrap()); + } else { + result.addReadDefinition(def.asReadFromMqttDefinition().wrap()); + } + } + for (MappingDefinition def : allMappingDefinitions()) { + result.addMappingDefinition(def.wrap()); + } + for (DependencyDefinition def : getDependencyDefinitionList()) { + result.addDependencyDefinition(def.wrap()); + } + for (TokenComponent token : getProgram().allTokenComponents()) { + result.addTokenComponent(token.wrap()); + } + return result; + } +//MInnerMappingDefinition.MappingDefinition -> MappingDefinition; + private void MUpdateDefinition.addInnerMappings() { + for (MappingDefinition def : updateDefinition().effectiveMappings()) { + addInnerMappingDefinition(def.wrap()); + } + } + syn lazy MReadDefinition ReadFromMqttDefinition.wrap() { + MReadDefinition result = new MReadDefinition(); + result.setReadFromMqttDefinition(this); + result.addInnerMappings(); + return result; + } + syn lazy MWriteDefinition WriteToMqttDefinition.wrap() { + MWriteDefinition result = new MWriteDefinition(); + result.setWriteToMqttDefinition(this); + result.addInnerMappings(); + return result; + } + syn lazy MMappingDefinition MappingDefinition.wrap() { + MMappingDefinition result = new MMappingDefinition(); + result.setMappingDefinition(this); + return result; + } + syn lazy MDependencyDefinition DependencyDefinition.wrap() { + MDependencyDefinition result = new MDependencyDefinition(); + result.setDependencyDefinition(this); + return result; + } + syn lazy MTypeComponent TypeComponent.wrap() { + MTypeComponent result = new MTypeComponent(); + result.setTypeComponent(this); + for (DependencyDefinition def : getDependencySourceDefinitionList()) { + result.addDependencyDefinition(def.wrap()); + } + return result; + } +} + aspect AspectGeneration { // naming convention attributes syn String TokenComponent.internalName() = getDependencySourceDefinitionList().isEmpty() ? externalName() : "_internal_" + getName(); diff --git a/src/main/resources/dependencyDefinition.mustache b/src/main/resources/dependencyDefinition.mustache new file mode 100644 index 0000000000000000000000000000000000000000..b8d74ffe8f8aa5aaa8979682e4442215af1974e8 --- /dev/null +++ b/src/main/resources/dependencyDefinition.mustache @@ -0,0 +1,3 @@ + public void {{targetParentTypeName}}.{{dependencyMethod}}({{sourceParentTypeName}} source) { + add{{internalRelationPrefix}}Source(source); + } diff --git a/src/main/resources/mappingApplication.mustache b/src/main/resources/mappingApplication.mustache new file mode 100644 index 0000000000000000000000000000000000000000..61020400b11622dd09069118c50e6b42c166dcaf --- /dev/null +++ b/src/main/resources/mappingApplication.mustache @@ -0,0 +1,14 @@ +{{lastDefinitionToType}} {{resultVarPrefix}}{{lastDefinitionName}}; +try { + {{#InnerMappingDefinitions}} + {{^isLast}}{{ToType}} {{/isLast}}{{resultVarPrefix}}{{methodName}} = {{methodName}}({{inputVarName}});{{!inputVarName has to be computed beforehand}} + {{/InnerMappingDefinitions}} +} catch (Exception e) { + e.printStackTrace(); + {{preemptiveReturn}} +} +{{^alwaysApply}} +if ({{condition}}) { + {{preemptiveReturn}} +} +{{/alwaysApply}} diff --git a/src/main/resources/mappingDefinition.mustache b/src/main/resources/mappingDefinition.mustache new file mode 100644 index 0000000000000000000000000000000000000000..5cc1580a724bc75a15bbdf896974b7dcaa8c926a --- /dev/null +++ b/src/main/resources/mappingDefinition.mustache @@ -0,0 +1,3 @@ + protected static {{toType}} ASTNode.{{methodName}}({{fromType}} {{fromVariableName}}) throws Exception { + {{content}}{{!maybe print line by line to get better indentation}} + } diff --git a/src/main/resources/readDefinition.mustache b/src/main/resources/readDefinition.mustache new file mode 100644 index 0000000000000000000000000000000000000000..4d07c8fa2d1464ad774badfa02d9b5e1ac774e7e --- /dev/null +++ b/src/main/resources/readDefinition.mustache @@ -0,0 +1,9 @@ + 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}}); + }); + } diff --git a/src/main/resources/ros2rag.mustache b/src/main/resources/ros2rag.mustache new file mode 100644 index 0000000000000000000000000000000000000000..b224c6c1018fd405ca2a5802e544295e3a5a7cfa --- /dev/null +++ b/src/main/resources/ros2rag.mustache @@ -0,0 +1,21 @@ +aspect ROS2RAG { + {{#ReadDefinitions}} + {{> readDefinition}} + {{/ReadDefinitions}} + + {{#WriteDefinitions}} + {{> writeDefinition}} + {{/WriteDefinitions}} + + {{#MappingDefinitions}} + {{> mappingDefinition}} + {{/MappingDefinitions}} + + {{#DependencyDefinitions}} + {{> dependencyDefinition}} + {{/DependencyDefinitions}} + + {{#TokenComponents}} + {{> tokenComponent}} + {{/TokenComponents}} +} diff --git a/src/main/resources/tokenComponent.mustache b/src/main/resources/tokenComponent.mustache new file mode 100644 index 0000000000000000000000000000000000000000..1e58287748affc8405e4daf47ff1b54d3f19f12e --- /dev/null +++ b/src/main/resources/tokenComponent.mustache @@ -0,0 +1,17 @@ + public {{parentTypeName}} {{parentTypeName}}.set{{name}}({{javaType}} value) { + set{{internalName}}(value); + {{#DependencyDefinitions}} + for ({{targetParentType}} target : get{{internalRelationPrefix}}TargetList) { + {{#targetUpdateDefinition}} + if (target.{{updateMethod}}()) { + target.{{writeMethod}}(); + } + {{/targetUpdateDefinition}} + } + {{/DependencyDefinitions}} + return this; + } + + public {{javaType}} {{parentTypeName}}.get{{name}}() { + return get{{internalName}}(); + } diff --git a/src/main/resources/writeDefinition.mustache b/src/main/resources/writeDefinition.mustache new file mode 100644 index 0000000000000000000000000000000000000000..d94f85d51d679cd4571979664cdcfc53fc28cc1a --- /dev/null +++ b/src/main/resources/writeDefinition.mustache @@ -0,0 +1,24 @@ + 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}} + {{mqttUpdateAttribute}}().publish({{writeTopic}}, {{lastValue}}); + }