Commit ceff6575 authored by René Schöne's avatar René Schöne
Browse files

Begin with real generation.

- Compiler: replace existing files if needed
- Renamed Aspect.jadd to Generation.jadd and fill it with content
- Missing: Generation of dependency relation, and change of token names in grammar
parent 62eb85ab
Pipeline #6515 passed with stage
in 1 minute and 41 seconds
aspect Analysis {
// --- isPrimitiveType ---
syn boolean TokenComponent.isPrimitiveType() = getJavaTypeUse().isPrimitiveType();
syn boolean JavaTypeUse.isPrimitiveType() = false;
eq SimpleJavaTypeUse.isPrimitiveType() {
switch(getName()) {
case "short":
case "int":
case "float":
case "double":
case "char":
case "byte": return true;
default: return false;
}
}
// --- prettyPrint ---
syn String MappingDefinitionType.prettyPrint();
eq JavaMappingDefinitionType.prettyPrint() = getType().getName();
eq JavaArrayMappingDefinitionType.prettyPrint() = getType().getName() + "[]";
}
......@@ -35,6 +35,12 @@ aspect Navigation {
// --- containedFile ---
inh GrammarFile ASTNode.containedFile();
eq GrammarFile.getChild().containedFile() = this;
eq Program.getChild().containedFile() = null;
eq Ros2Rag.getChild().containedFile() = null;
// --- isTypeComponent ---
syn boolean Component.isTypeComponent() = false;
eq TypeComponent.isTypeComponent() = true;
// --- isTokenComponent ---
syn boolean Component.isTokenComponent() = false;
......@@ -43,4 +49,24 @@ aspect Navigation {
// --- asTokenComponent ---
syn TokenComponent Component.asTokenComponent() = null;
eq TokenComponent.asTokenComponent() = this;
// --- isWriteToMqttDefinition ---
syn boolean UpdateDefinition.isWriteToMqttDefinition() = false;
eq WriteToMqttDefinition.isWriteToMqttDefinition() = true;
// --- asWriteToMqttDefinition ---
syn WriteToMqttDefinition UpdateDefinition.asWriteToMqttDefinition() = null;
eq WriteToMqttDefinition.asWriteToMqttDefinition() = this;
// --- targetUpdateDefinition ---
syn WriteToMqttDefinition DependencyDefinition.targetUpdateDefinition() {
// resolve definition in here, as we do not need resolveMethod in any other place (yet)
for (UpdateDefinition updateDefinition : ros2rag().getUpdateDefinitionList()) {
if (updateDefinition.isWriteToMqttDefinition() &&
updateDefinition.asWriteToMqttDefinition().getToken().equals(this.getTarget())) {
return updateDefinition.asWriteToMqttDefinition();
}
}
return null;
}
}
......@@ -8,7 +8,6 @@ Ros2Rag ros2rag
%embed {:
private Iterable<String> makeMappingDefs(ArrayList<?> raw_mapping_defs) {
java.util.Collections.reverse(raw_mapping_defs);
return () -> raw_mapping_defs.stream().map(raw -> ((Symbol) raw).value.toString()).iterator();
}
:} ;
......
Ros2Rag ::= UpdateDefinition* DependencyDefinition* MappingDefinition* Program;
abstract UpdateDefinition ::= <AlwaysApply:Boolean> ;
abstract UpdateDefinition ::= <AlwaysApply:boolean> ;
rel UpdateDefinition.Mapping* -> MappingDefinition;
......
aspect Aspect {
public static final String ASTNode.aspectIndent = " ";
public String Program.generateAspect() {
StringBuilder sb = new StringBuilder();
generateAspect(sb);
return sb.toString();
}
@Deprecated
public void Program.generateAspect(StringBuilder sb) {
sb.append("aspect ROS2RAG {\n");
// TODO generate getters and setters for ROS2RAG terminals (and attributes?)
sb.append("}\n");
}
public String Ros2Rag.generateAspect(String rootNodeName) {
StringBuilder sb = new StringBuilder();
generateMqttAspect(sb);
generateGrammarExtension(sb);
return sb.toString();
}
public void Ros2Rag.generateMqttAspect(StringBuilder sb) {
}
// from "[always] read Joint.CurrentPosition using PoseToPosition;" generate method connectTo
// Joint j;
// j.getCurrentPosition().connectTo("/robot/joint2/pos");
public void Ros2Rag.generateGrammarExtension(StringBuilder sb) {
sb.append("aspect ros2rag.GrammarExtension {\n");
for (UpdateDefinition def : getUpdateDefinitionList()) {
def.generateAspect(sb);
}
sb.append("}\n");
}
abstract void UpdateDefinition.generateAspect(StringBuilder sb);
// @Override
// void UpdateDefinition.generateAspect(StringBuilder sb) {
// // TODO
// }
// will be "addConnectionJoint_CurrentPosition" in example
/* // see discussion in codimd (InstanceLocation), why this won't work here
Position.connectTo(String topic) {
mqttUpdater().addConnectionJoint_CurrentPosition(this, topic);
}
MqttUpdater.addConnectionJoint_CurrentPosition(Position target, String topic) {
// either
topicActionMap.put(topic, new Action(JOINT_CURRENTPOSITION, target));
// or
topicForJoint_CurrentPosition.put(topic, target);
}
*/
@Override
void ReadFromMqttDefinition.generateAspect(StringBuilder sb) {
sb.append("public void ").append("type").append(".connectTo(String topic) {\n")
.append(aspectIndent).append("mqttUpdater().addConnection")
.append(getToken().containingTypeDecl().getName())
.append("_")
.append(getToken().getName())
.append("(this, topic);\n")
.append("}\n");
}
@Override
void WriteToMqttDefinition.generateAspect(StringBuilder sb) {
sb.append("public void ").append("type").append(".connectTo(String topic) {\n")
.append(aspectIndent).append("mqttUpdater().addConnection")
.append(getToken().containingTypeDecl().getName())
.append("_")
.append(getToken().getName())
.append("(this, topic);\n")
.append("}\n");
}
}
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();
}
}
aspect AspectGeneration {
// naming convention attributes
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() = "_internal" + getSource().getName();
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.mqttUpdaterField() = "_mqttUpdater";
syn String Ros2Rag.mqttSetHostMethod() = "MqttSetHost";
syn String Ros2Rag.mqttWaitUntilReadyMethod() = "MqttWaitUntilReady";
syn String Ros2Rag.mqttCloseMethod() = "MqttCloseConnections";
public String Ros2Rag.generateAspect(String rootNodeName) {
StringBuilder sb = new StringBuilder();
TypeDecl rootNode = getProgram().resolveTypeDecl(rootNodeName);
generateMqttAspect(sb, rootNode);
generateGrammarExtension(sb);
return sb.toString();
}
public void Ros2Rag.generateMqttAspect(StringBuilder sb, TypeDecl rootNode) {
String rootNodeName = rootNode.getName();
sb.append("aspect MQTT {\n");
sb.append(ind(1)).append("private static final int ")
.append(rootNodeName).append("._MQTT_DEFAULT_PORT = 1883;\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("MqttSetHost(host, _MQTT_DEFAULT_PORT);\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 void ").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.GrammarExtension {\n");
for (UpdateDefinition def : getUpdateDefinitionList()) {
def.generateAspect(sb);
}
for (MappingDefinition def : getMappingDefinitionList()) {
def.generateAspect(sb);
}
for (DependencyDefinition def : getDependencyDefinitionList()) {
def.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;
for (MappingDefinition mappingDefinition : getMappingList()) {
String resultVariableName = resultVariablePrefix + mappingDefinition.methodName();
sb.append(ind(indent)).append(mappingDefinition.getToType().prettyPrint()).append(" ")
.append(resultVariablePrefix).append(mappingDefinition.methodName())
.append(" = ").append(mappingDefinition.methodName()).append("(")
.append(inputVariableName).append(");\n");
inputVariableName = resultVariableName;
}
if (!getAlwaysApply()) {
sb.append(ind(indent)).append("if (get").append(getToken().getName()).append("()");
if (getToken().isPrimitiveType()) {
sb.append(" == ").append(inputVariableName);
} else {
sb.append(" != null ? get").append(getToken().getName()).append("().equals(")
.append(inputVariableName).append(")").append(" : ")
.append(inputVariableName).append(" == null");
}
sb.append(") { ").append(preemptiveReturnStatement()).append(" }\n");
}
return inputVariableName;
}
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");
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");
// _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(") {\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");
// virtual setter
sb.append(ind(1)).append("public ").append(sourceParentTypeName).append(" ")
.append(sourceParentTypeName).append(".set").append(getSource().getName()).append("(");
getSource().getJavaTypeUse().generateAbstractGrammar(sb);
sb.append(" value) {\n");
sb.append(ind(2)).append("set").append(internalTokenName()).append("(value);\n");
sb.append(ind(2)).append("for (").append(targetParentTypeName).append(" target : get")
.append(internalRelationPrefix()).append("TargetList()) {\n");
sb.append(ind(3)).append("if (target.").append(targetUpdateDefinition().updateMethod()).append("()) {\n");
sb.append(ind(4)).append("target.").append(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 ");
getSource().getJavaTypeUse().generateAbstractGrammar(sb);
sb.append(" ").append(sourceParentTypeName).append(".get").append(getSource().getName()).append("() {\n");
sb.append(ind(2)).append("return get").append(internalTokenName()).append(";\n");
sb.append(ind(1)).append("}\n\n");
}
}
......@@ -12,6 +12,7 @@ import org.jastadd.ros2rag.scanner.Ros2RagScanner;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.List;
......@@ -59,7 +60,8 @@ public class Compiler {
// copy MqttUpdater into outputDir
try {
Files.copy(Paths.get("src", "main", "jastadd", "MqttUpdater.java_class"),
Paths.get(outputDir, "MqttUpdater.java"));
Paths.get(outputDir, "MqttUpdater.java"),
StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
throw new CompilerException("Could not copy MqttUpdater.java", e);
}
......
......@@ -4,7 +4,7 @@ ZoneModel ::= <Size:IntPosition> SafetyZone:Zone* ;
Zone ::= Coordinate* ;
RobotArm ::= Joint* EndEffector <_AttributeTestSource:int> /<_AppropriateSpeed:double>/ ; // normally this would be: <AttributeTestSource:int> ;
RobotArm ::= Joint* EndEffector <AttributeTestSource:int> /<AppropriateSpeed:double>/ ; // normally this would be: <AttributeTestSource:int> ;
Joint ::= <Name> <CurrentPosition:IntPosition> ; // normally this would be: <CurrentPosition:IntPosition>
......
/* Version 2020-04-17 */
// --- update definitions ---
read Joint.CurrentPosition using ParseLinkState, LinkStateToIntPosition ;
write RobotArm._AppropriateSpeed using CreateSpeedMessage, SerializeRobotConfig ;
write RobotArm.AppropriateSpeed using CreateSpeedMessage, SerializeRobotConfig ;
// --- dependency definitions ---
RobotArm._AppropriateSpeed canDependOn Joint.CurrentPosition as dependency1 ;
RobotArm._AppropriateSpeed canDependOn RobotArm._AttributeTestSource as dependency2 ;
RobotArm.AppropriateSpeed canDependOn Joint.CurrentPosition as dependency1 ;
RobotArm.AppropriateSpeed canDependOn RobotArm.AttributeTestSource as dependency2 ;
// --- mapping definitions ---
ParseLinkState maps byte[] bytes to panda.Linkstate.PandaLinkState {:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment