Generation.jadd 10.9 KB
Newer Older
René Schöne's avatar
René Schöne committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
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) {
René Schöne's avatar
René Schöne committed
93
    sb.append("aspect ROS2RAG {\n");
René Schöne's avatar
René Schöne committed
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146

    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");
René Schöne's avatar
René Schöne committed
147
    sb.append(ind(2)).append("});\n");
René Schöne's avatar
René Schöne committed
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
    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
René Schöne's avatar
René Schöne committed
171
    sb.append(ind(1)).append("protected boolean ").append(parentTypeName).append(".")
René Schöne's avatar
René Schöne committed
172
173
174
175
176
177
178
179
      .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
René Schöne's avatar
René Schöne committed
180
    sb.append(ind(1)).append("protected void ").append(parentTypeName).append(".")
René Schöne's avatar
René Schöne committed
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
      .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
René Schöne's avatar
René Schöne committed
205
    sb.append(ind(1)).append("public void ").append(targetParentTypeName).append(".")
René Schöne's avatar
René Schöne committed
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
      .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");
  }
}