From ceff6575ce2c7f5292c344eafdcc062a1ea4f2d6 Mon Sep 17 00:00:00 2001
From: rschoene <rene.schoene@tu-dresden.de>
Date: Mon, 4 May 2020 21:36:01 +0200
Subject: [PATCH] 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
---
 ros2rag.base/src/main/jastadd/Analysis.jrag   |  19 ++
 ros2rag.base/src/main/jastadd/Navigation.jrag |  26 ++
 ros2rag.base/src/main/jastadd/Ros2Rag.parser  |   1 -
 ros2rag.base/src/main/jastadd/Ros2Rag.relast  |   2 +-
 .../src/main/jastadd/backend/Aspect.jadd      |  86 -------
 .../src/main/jastadd/backend/Generation.jadd  | 232 ++++++++++++++++++
 .../jastadd/ros2rag/compiler/Compiler.java    |   4 +-
 .../src/test/resources/Example.relast         |   2 +-
 .../src/test/resources/Example.ros2rag        |   6 +-
 9 files changed, 285 insertions(+), 93 deletions(-)
 delete mode 100644 ros2rag.base/src/main/jastadd/backend/Aspect.jadd
 create mode 100644 ros2rag.base/src/main/jastadd/backend/Generation.jadd

diff --git a/ros2rag.base/src/main/jastadd/Analysis.jrag b/ros2rag.base/src/main/jastadd/Analysis.jrag
index 118dd23..246645f 100644
--- a/ros2rag.base/src/main/jastadd/Analysis.jrag
+++ b/ros2rag.base/src/main/jastadd/Analysis.jrag
@@ -1,3 +1,22 @@
 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() + "[]";
 
 }
diff --git a/ros2rag.base/src/main/jastadd/Navigation.jrag b/ros2rag.base/src/main/jastadd/Navigation.jrag
index 4b233c2..b401112 100644
--- a/ros2rag.base/src/main/jastadd/Navigation.jrag
+++ b/ros2rag.base/src/main/jastadd/Navigation.jrag
@@ -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;
+  }
 }
diff --git a/ros2rag.base/src/main/jastadd/Ros2Rag.parser b/ros2rag.base/src/main/jastadd/Ros2Rag.parser
index 750e0ce..f2ab264 100644
--- a/ros2rag.base/src/main/jastadd/Ros2Rag.parser
+++ b/ros2rag.base/src/main/jastadd/Ros2Rag.parser
@@ -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();
   }
 :} ;
diff --git a/ros2rag.base/src/main/jastadd/Ros2Rag.relast b/ros2rag.base/src/main/jastadd/Ros2Rag.relast
index f8465bb..1669503 100644
--- a/ros2rag.base/src/main/jastadd/Ros2Rag.relast
+++ b/ros2rag.base/src/main/jastadd/Ros2Rag.relast
@@ -1,6 +1,6 @@
 Ros2Rag ::= UpdateDefinition* DependencyDefinition* MappingDefinition* Program;
 
-abstract UpdateDefinition ::= <AlwaysApply:Boolean> ;
+abstract UpdateDefinition ::= <AlwaysApply:boolean> ;
 
 rel UpdateDefinition.Mapping* -> MappingDefinition;
 
diff --git a/ros2rag.base/src/main/jastadd/backend/Aspect.jadd b/ros2rag.base/src/main/jastadd/backend/Aspect.jadd
deleted file mode 100644
index 1cf2fd9..0000000
--- a/ros2rag.base/src/main/jastadd/backend/Aspect.jadd
+++ /dev/null
@@ -1,86 +0,0 @@
-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");
-  }
-
-}
diff --git a/ros2rag.base/src/main/jastadd/backend/Generation.jadd b/ros2rag.base/src/main/jastadd/backend/Generation.jadd
new file mode 100644
index 0000000..3195a70
--- /dev/null
+++ b/ros2rag.base/src/main/jastadd/backend/Generation.jadd
@@ -0,0 +1,232 @@
+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");
+  }
+}
diff --git a/ros2rag.base/src/main/java/org/jastadd/ros2rag/compiler/Compiler.java b/ros2rag.base/src/main/java/org/jastadd/ros2rag/compiler/Compiler.java
index 006f1d1..f9b6f5f 100644
--- a/ros2rag.base/src/main/java/org/jastadd/ros2rag/compiler/Compiler.java
+++ b/ros2rag.base/src/main/java/org/jastadd/ros2rag/compiler/Compiler.java
@@ -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);
     }
diff --git a/ros2rag.base/src/test/resources/Example.relast b/ros2rag.base/src/test/resources/Example.relast
index aa17ad8..93168fb 100644
--- a/ros2rag.base/src/test/resources/Example.relast
+++ b/ros2rag.base/src/test/resources/Example.relast
@@ -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>
 
diff --git a/ros2rag.base/src/test/resources/Example.ros2rag b/ros2rag.base/src/test/resources/Example.ros2rag
index f17a9be..9168da2 100644
--- a/ros2rag.base/src/test/resources/Example.ros2rag
+++ b/ros2rag.base/src/test/resources/Example.ros2rag
@@ -1,11 +1,11 @@
 /* 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 {:
-- 
GitLab