aspect GenerationUtils { public static final String ASTNode.aspectIndent = " "; public String ASTNode.ind(int n) { StringBuilder s = new StringBuilder(); for (int i = 0; i < n; i++) { s.append(aspectIndent); } return s.toString(); } // --- prettyPrint --- syn String MappingDefinitionType.prettyPrint(); eq JavaMappingDefinitionType.prettyPrint() = getType().getName(); eq JavaArrayMappingDefinitionType.prettyPrint() = getType().getName() + "[]"; syn String JavaTypeUse.prettyPrint() { StringBuilder sb = new StringBuilder(); generateAbstractGrammar(sb); return sb.toString(); } } /* 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 TokenUpdateDefinition MUpdateDefinition.updateDef(); syn String MUpdateDefinition.firstInputVarName(); eq MUpdateDefinition.getInnerMappingDefinition(int i).isLast() = i == getNumInnerMappingDefinition(); eq MUpdateDefinition.getInnerMappingDefinition().resultVarPrefix() = resultVarPrefix(); eq MUpdateDefinition.getInnerMappingDefinition(int i).inputVarName() = i == 0 ? firstInputVarName() : resultVarPrefix() + getInnerMappingDefinition(i - 1).getMappingDefinition().methodName(); eq MRos2Rag.getChild().mqttUpdaterField() = getRos2Rag().mqttUpdaterField(); syn String MUpdateDefinition.mqttUpdaterAttribute() = updateDef().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.lastDefinitionType() = 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()) { result.addTokenComponent(token.toMustache()); } for (Component child : rootNode.getComponentList()) { if (child.isTypeComponent()) { result.addRootTypeChildren(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 { // naming convention attributes syn String TokenComponent.internalName() = getDependencySourceDefinitionList().isEmpty() ? externalName() : "_internal_" + getName(); syn String TokenComponent.externalName() = getName(); syn String TokenUpdateDefinition.connectMethod() = "connect" + getToken().getName(); syn String WriteToMqttDefinition.writeTopic() = "_topic_" + getToken().getName(); syn String WriteToMqttDefinition.lastValue() = "_lastValue" + getToken().getName(); syn String WriteToMqttDefinition.updateMethod() = "_update_" + getToken().getName(); syn String WriteToMqttDefinition.writeMethod() = "_writeLastValue_" + getToken().getName(); syn String WriteToMqttDefinition.tokenResetMethod() = "get" + getToken().getName() + "_reset"; syn String MappingDefinition.methodName() = "_apply_" + getID(); syn String DependencyDefinition.dependencyMethod() = "add" + Character.toUpperCase(getID().charAt(0)) + getID().substring(1); syn String DependencyDefinition.internalRelationPrefix() = "_internal_" + getID(); syn String DependencyDefinition.internalTokenName() = getSource().internalName(); syn String Ros2Rag.mqttUpdaterAttribute() = "_mqttUpdater"; syn String Ros2Rag.mqttUpdaterField() = "_mqttUpdater"; syn String Ros2Rag.mqttSetHostMethod() = "MqttSetHost"; syn String Ros2Rag.mqttWaitUntilReadyMethod() = "MqttWaitUntilReady"; syn String Ros2Rag.mqttCloseMethod() = "MqttCloseConnections"; // naming copy attributes // --- mqttUpdaterAttribute --- inh String UpdateDefinition.mqttUpdaterAttribute(); inh String MappingDefinition.mqttUpdaterAttribute(); inh String DependencyDefinition.mqttUpdaterAttribute(); eq Ros2Rag.getChild().mqttUpdaterAttribute() = mqttUpdaterAttribute(); // --- mqttUpdaterField --- // --- rootNodeName --- syn String ASTNode.rootNodeName() = rootNode.getName(); // mustache specific nodes // syn nta TypeComponentMustache TypeComponent.mustache() { // TypeComponentMustache result = new TypeComponentMustache(); // result.setTypeComponent(this); // return result; // } // syn String TypeComponentMustache.name() = getTypeComponent().getName(); // inh String TypeComponentMustache.mqttUpdaterAttribute(); // inh String TypeComponentMustache.mqttUpdaterField(); // // // mustache specific attributes // syn java.util.List Ros2Rag.rootTypeChildren() { // java.util.List result = new java.util.ArrayList<>(); // for (Component child : rootNode.getComponentList()) { // if (child.isTypeComponent()){ // result.add(child.asTypeComponent().mustache()); // } // } // return result; // } public String Ros2Rag.generateAspect(String rootNodeName) { StringBuilder sb = new StringBuilder(); rootNode = getProgram().resolveTypeDecl(rootNodeName); com.github.mustachejava.MustacheFactory mf = new com.github.mustachejava.DefaultMustacheFactory(); com.github.mustachejava.Mustache m = mf.compile("ros2rag.mustache"); m.execute(new java.io.PrintWriter(new org.jastadd.ros2rag.compiler.AppendableWriter(sb)), this); // generateMqttAspect(sb); // generateGrammarExtension(sb); return sb.toString(); } // // public void Ros2Rag.generateMqttAspect(StringBuilder sb) { // String rootNodeName = rootNode.getName(); // com.github.mustachejava.MustacheFactory mf = new com.github.mustachejava.DefaultMustacheFactory(); // com.github.mustachejava.Mustache m = mf.compile("mqtt.mustache"); // m.execute(new java.io.PrintWriter(new org.jastadd.ros2rag.compiler.AppendableWriter(sb)), this); // } // // 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); // // String TokenUpdateDefinition.generateMappingApplication(StringBuilder sb, int indent, // String initialInputVariableName) { // final String resultVariablePrefix = "result"; // we do not need "_" here, because methodName begins with one // 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(); // eq ReadFromMqttDefinition.preemptiveExpectedValue() = "get" + getToken().getName() + "()"; // eq WriteToMqttDefinition.preemptiveExpectedValue() = lastValue(); // // syn String TokenUpdateDefinition.preemptiveReturnStatement(); // eq ReadFromMqttDefinition.preemptiveReturnStatement() = "return;"; // eq WriteToMqttDefinition.preemptiveReturnStatement() = "return false;"; // // @Override // void ReadFromMqttDefinition.generateAspect(StringBuilder sb) { // sb.append(ind(1)).append("public void ").append(getToken().containingTypeDecl().getName()).append(".") // .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 // void WriteToMqttDefinition.generateAspect(StringBuilder sb) { // String parentTypeName = getToken().containingTypeDecl().getName(); // // fields // sb.append(ind(1)).append("private String ").append(parentTypeName).append(".") // .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"); // } // // 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) { // if (getDependencySourceDefinitionList().isEmpty()) { return; } // // String parentTypeName = containingTypeDecl().getName(); // // virtual setter // 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"); // } } aspect RelationGeneration { syn java.util.List Ros2Rag.additionalRelations() { java.util.List result = new java.util.ArrayList<>(); for (DependencyDefinition dd : getDependencyDefinitionList()) { result.add(dd.getRelationToCreate()); } return result; } syn nta Relation DependencyDefinition.getRelationToCreate() { BidirectionalRelation result = new BidirectionalRelation(); NavigableRole left = new ListRole(internalRelationPrefix() + "Source"); left.setType(getTarget().containingTypeDecl()); NavigableRole right = new ListRole(internalRelationPrefix() + "Target"); right.setType(getSource().containingTypeDecl()); result.setLeft(left); result.setRight(right); return result; } } aspect GrammarExtension { refine BackendAbstractGrammar public void TokenComponent.generateAbstractGrammar(StringBuilder b) { if (getNTA()) { b.append("/"); } b.append("<"); if (!getName().equals("")) { b.append(internalName()).append(":"); } getJavaTypeUse().generateAbstractGrammar(b); b.append(">"); if (getNTA()) { b.append("/"); } } }