Commit f6cb3ef9 authored by Alexander David Hellwig's avatar Alexander David Hellwig
Browse files

Added tests + support for the simple structs

parent bbd65fa2
package de.monticore.lang.monticar.generator.rosmsg;
import de.monticore.lang.monticar.struct._symboltable.StructFieldDefinitionSymbol;
import de.monticore.lang.monticar.struct._symboltable.StructSymbol;
import de.monticore.lang.monticar.ts.MCASTTypeSymbol;
import de.monticore.lang.monticar.ts.MCTypeSymbol;
import de.monticore.lang.monticar.ts.MontiCarTypeSymbol;
import de.monticore.lang.monticar.ts.references.MCTypeReference;
import de.se_rwth.commons.logging.Log;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public class GeneratorRosMsg {
private String path;
private String packageName;
private Set<String> alreadyGenerated = new HashSet<>();
public List<File> generate(MCTypeReference<? extends MCTypeSymbol> typeReference){
if(!typeReference.existsReferencedSymbol()) return new ArrayList<>();
ArrayList<File> files = new ArrayList<>();
public void setTarget(String path, String packageName) {
if (path.endsWith("/")) {
this.path = path + "/";
} else {
this.path = path;
}
MCTypeSymbol type = typeReference.getReferencedSymbol();
if(type.isKindOf(MCASTTypeSymbol.KIND)){
//Not needed, std_msgs already generated
this.packageName = packageName;
}
public List<File> generate(MCTypeReference<? extends MCTypeSymbol> typeReference) throws IOException {
//is typeReference basic type or struct?
if (getRosType(typeReference) != null) {
MCTypeSymbol type = typeReference.getReferencedSymbol();
List<File> res = new ArrayList<>();
if (type instanceof StructSymbol) {
res.addAll(generateStruct((StructSymbol) type));
}
return res;
}
Log.error("Cannot generate .msg file(s) for " + typeReference);
return new ArrayList<>();
}
public List<File> generateStruct(StructSymbol structSymbol) throws IOException {
if (alreadyGenerated.contains(packageName + "/" + getTargetName(structSymbol))) {
Log.debug("Struct " + structSymbol + " was already generated!", "structGeneration");
return new ArrayList<>();
}
alreadyGenerated.add(packageName + "/" + getTargetName(structSymbol));
List<File> files = new ArrayList<>();
String definition = structSymbol.getStructFieldDefinitions().stream()
.filter(sfds -> sfds.getType().existsReferencedSymbol())
.map(sfds -> getInMsgRosType(sfds.getType().getReferencedSymbol()) + " " + sfds.getName() + ";")
.collect(Collectors.joining("\n"));
File f = new File(path + "/" + getTargetName(structSymbol) + ".msg");
FileUtils.write(f, definition);
//recursively generated needed .msg from nested structs
for (StructFieldDefinitionSymbol sfds : structSymbol.getStructFieldDefinitions()) {
if (sfds.getType().existsReferencedSymbol()) {
if (sfds.getType().getReferencedSymbol() instanceof StructSymbol) {
StructSymbol referencedSymbol = (StructSymbol) sfds.getType().getReferencedSymbol();
generateStruct(referencedSymbol);
}
}
}
return files;
}
private String getInMsgRosType(MCTypeSymbol referencedSymbol) {
if (referencedSymbol.isKindOf(MontiCarTypeSymbol.KIND)) {
MontiCarTypeSymbol mcastTypeSymbol = (MontiCarTypeSymbol) referencedSymbol;
if (mcastTypeSymbol.getName().equals("Q")) {
return "float64";
} else if (mcastTypeSymbol.getName().equals("Z")) {
return "int32";
} else if (mcastTypeSymbol.getName().equals("B")) {
return "boolean";
} else {
Log.error("Case not handled! MCASTTypeSymbol " + mcastTypeSymbol.getName());
}
}
if (referencedSymbol instanceof StructSymbol) {
StructSymbol structSymbol = (StructSymbol) referencedSymbol;
if (packageName == null)
Log.error("Target must be set! Use GeneratorRosMsg::setTarget!");
return packageName + "/" + getTargetName(structSymbol);
}
Log.error("Case not handled! MCTypeReference " + referencedSymbol);
return null;
}
public String getRosType(MCTypeReference<? extends MCTypeSymbol> typeReference){
MCTypeSymbol type = typeReference.getReferencedSymbol();
if(type.isKindOf(MCASTTypeSymbol.KIND)){
......@@ -40,10 +118,19 @@ public class GeneratorRosMsg {
}
}
if (type.isKindOf(StructSymbol.KIND)) {
StructSymbol structSymbol = (StructSymbol) type;
if (packageName == null)
Log.error("Target must be set! Use GeneratorRosMsg::setTarget!");
return packageName + "/" + getTargetName(structSymbol);
}
Log.error("Case not handled! MCTypeReference " + typeReference);
return null;
}
private String getTargetName(StructSymbol structSymbol) {
return structSymbol.getFullName().replace(".", "_");
}
}
......@@ -5,15 +5,19 @@ import de.monticore.lang.embeddedmontiarc.embeddedmontiarc._symboltable.PortSymb
import de.monticore.symboltable.Scope;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
public class BasicTypesTest extends AbstractSymtabTest {
@Test
public void testBasicTypes(){
public void testBasicTypes() throws IOException {
Scope symtab = createSymTab("src/test/resources/");
ExpandedComponentInstanceSymbol component = symtab.<ExpandedComponentInstanceSymbol>resolve("tests.basicTypes", ExpandedComponentInstanceSymbol.KIND).orElse(null);
ExpandedComponentInstanceSymbol component = symtab.<ExpandedComponentInstanceSymbol>resolve("tests.basicTypesComp", ExpandedComponentInstanceSymbol.KIND).orElse(null);
assertNotNull(component);
GeneratorRosMsg generatorRosMsg = new GeneratorRosMsg();
......@@ -31,5 +35,68 @@ public class BasicTypesTest extends AbstractSymtabTest {
assertEquals(generatorRosMsg.getRosType(inB.getTypeReference()),"std_msgs/Bool");
}
@Test
public void testBasicStructComp() throws IOException {
Scope symtab = createSymTab("src/test/resources/");
ExpandedComponentInstanceSymbol component = symtab.<ExpandedComponentInstanceSymbol>resolve("tests.basicStructComp", ExpandedComponentInstanceSymbol.KIND).orElse(null);
assertNotNull(component);
GeneratorRosMsg generatorRosMsg = new GeneratorRosMsg();
generatorRosMsg.setTarget("target/generated-sources-rosmsg/basic", "basic");
PortSymbol in1 = component.getPort("in1").orElse(null);
PortSymbol out1 = component.getPort("out1").orElse(null);
assertNotNull(in1);
assertNotNull(out1);
assertEquals(generatorRosMsg.getRosType(in1.getTypeReference()), "basic/structs_BasicStruct");
assertEquals(generatorRosMsg.getRosType(out1.getTypeReference()), "basic/structs_BasicStruct");
List<File> files = generatorRosMsg.generate(in1.getTypeReference());
testFilesAreEqual(files, "basicStruct/");
}
@Test
public void testNestedStructComp() throws IOException {
Scope symtab = createSymTab("src/test/resources/");
ExpandedComponentInstanceSymbol component = symtab.<ExpandedComponentInstanceSymbol>resolve("tests.nestedStructComp", ExpandedComponentInstanceSymbol.KIND).orElse(null);
assertNotNull(component);
GeneratorRosMsg generatorRosMsg = new GeneratorRosMsg();
generatorRosMsg.setTarget("target/generated-sources-rosmsg/nested", "nested");
PortSymbol inNested = component.getPort("inNested").orElse(null);
assertNotNull(inNested);
assertEquals(generatorRosMsg.getRosType(inNested.getTypeReference()), "nested/structs_NestedStruct");
List<File> files = generatorRosMsg.generate(inNested.getTypeReference());
testFilesAreEqual(files, "nestedStruct/");
}
@Test
public void testMultiNestedStructComp() throws IOException {
Scope symtab = createSymTab("src/test/resources/");
ExpandedComponentInstanceSymbol component = symtab.<ExpandedComponentInstanceSymbol>resolve("tests.multiNestedStructComp", ExpandedComponentInstanceSymbol.KIND).orElse(null);
assertNotNull(component);
GeneratorRosMsg generatorRosMsg = new GeneratorRosMsg();
generatorRosMsg.setTarget("target/generated-sources-rosmsg/multinested", "multinested");
PortSymbol inMultiNested = component.getPort("inMultiNested").orElse(null);
assertNotNull(inMultiNested);
assertEquals(generatorRosMsg.getRosType(inMultiNested.getTypeReference()), "multinested/structs_MultiNestedStruct");
List<File> files = generatorRosMsg.generate(inMultiNested.getTypeReference());
testFilesAreEqual(files, "multinestedStruct/");
}
}
float64 fieldQ1;
float64 fieldQ2;
int32 fieldZ1;
int32 fieldZ2;
boolean fieldB1;
\ No newline at end of file
float64 fieldQ1;
float64 fieldQ2;
int32 fieldZ1;
int32 fieldZ2;
boolean fieldB1;
\ No newline at end of file
multinested/structs_NestedStruct fieldMultiNested1;
multinested/structs_NestedStruct fieldMultiNested2;
multinested/structs_BasicStruct fieldNested;
float64 fieldQ;
\ No newline at end of file
multinested/structs_BasicStruct fieldNested1;
multinested/structs_BasicStruct fieldNested2;
float64 fieldQ;
boolean fieldB;
int32 fieldZ;
\ No newline at end of file
float64 fieldQ1;
float64 fieldQ2;
int32 fieldZ1;
int32 fieldZ2;
boolean fieldB1;
\ No newline at end of file
nested/structs_BasicStruct fieldNested1;
nested/structs_BasicStruct fieldNested2;
float64 fieldQ;
boolean fieldB;
int32 fieldZ;
\ No newline at end of file
package structs;
struct BasicStruct{
Q fieldQ1;
Q (0:0.1:100) fieldQ2;
Z fieldZ1;
Z (-100:2:100) fieldZ2;
B fieldB1;
}
\ No newline at end of file
package structs;
struct MultiNestedStruct{
NestedStruct fieldMultiNested1;
NestedStruct fieldMultiNested2;
BasicStruct fieldNested;
Q fieldQ;
}
\ No newline at end of file
package structs;
struct NestedStruct{
BasicStruct fieldNested1;
BasicStruct fieldNested2;
Q fieldQ;
B fieldB;
Z fieldZ;
}
\ No newline at end of file
package tests;
import structs.BasicStruct;
component BasicStructComp{
ports in BasicStruct in1,
out BasicStruct out1;
}
\ No newline at end of file
package tests;
component BasicTypes{
component BasicTypesComp{
ports in Q inQ,
// in N inN,
in Z inZ,
......
package tests;
import structs.MultiNestedStruct;
component MultiNestedStructComp{
port in MultiNestedStruct inMultiNested;
}
\ No newline at end of file
package tests;
import structs.NestedStruct;
component NestedStructComp{
port in NestedStruct inNested;
}
\ No newline at end of file
Supports Markdown
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