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

Base: Begin with parser for ros2rag specification.

- changed compiler to accept two additional required parameters "inputGrammar" and "inputRos2Rag"
- update ros2rag grammar according to latest draft
- begin with parser (missing resolving amongst others)
- parsing in test kind of fails because of leading comment
parent 5aa98072
Pipeline #6394 passed with stage
in 1 minute and 11 seconds
...@@ -109,12 +109,13 @@ jastadd { ...@@ -109,12 +109,13 @@ jastadd {
} }
scanner { scanner {
include "src/main/jastadd/RelAst.flex" include "src/main/jastadd/Ros2Rag.flex"
} }
parser { parser {
include "src/main/jastadd/Preamble.parser" include "src/main/jastadd/Preamble.parser"
include "src/main/jastadd/RelAst.parser" include "src/main/jastadd/RelAst.parser"
include "src/main/jastadd/Ros2Rag.parser"
} }
} }
} }
......
...@@ -4,3 +4,4 @@ import org.jastadd.ros2rag.ast.*; ...@@ -4,3 +4,4 @@ import org.jastadd.ros2rag.ast.*;
:}; :};
%goal goal; %goal goal;
%goal ros2rag;
...@@ -49,6 +49,14 @@ ID = [a-zA-Z$_][a-zA-Z0-9$_]* ...@@ -49,6 +49,14 @@ ID = [a-zA-Z$_][a-zA-Z0-9$_]*
"abstract" { return sym(Terminals.ABSTRACT); } "abstract" { return sym(Terminals.ABSTRACT); }
"rel" { return sym(Terminals.RELATION); } "rel" { return sym(Terminals.RELATION); }
"read" { return sym(Terminals.READ); }
"write" { return sym(Terminals.WRITE); }
"using" { return sym(Terminals.USING); }
"canDependOn" { return sym(Terminals.CAN_DEPEND_ON); }
"maps" { return sym(Terminals.MAPS); }
"to" { return sym(Terminals.TO); }
"as" { return sym(Terminals.AS); }
";" { return sym(Terminals.SCOL); } ";" { return sym(Terminals.SCOL); }
":" { return sym(Terminals.COL); } ":" { return sym(Terminals.COL); }
"::=" { return sym(Terminals.ASSIGN); } "::=" { return sym(Terminals.ASSIGN); }
...@@ -59,6 +67,8 @@ ID = [a-zA-Z$_][a-zA-Z0-9$_]* ...@@ -59,6 +67,8 @@ ID = [a-zA-Z$_][a-zA-Z0-9$_]*
">" { return sym(Terminals.GT); } ">" { return sym(Terminals.GT); }
"[" { return sym(Terminals.LBRACKET); } "[" { return sym(Terminals.LBRACKET); }
"]" { return sym(Terminals.RBRACKET); } "]" { return sym(Terminals.RBRACKET); }
"{" { return sym(Terminals.LB_CURLY); }
"}" { return sym(Terminals.RB_CURLY); }
"/" { return sym(Terminals.SLASH); } "/" { return sym(Terminals.SLASH); }
"?" { return sym(Terminals.QUESTION_MARK); } "?" { return sym(Terminals.QUESTION_MARK); }
"->" { return sym(Terminals.RIGHT); } "->" { return sym(Terminals.RIGHT); }
......
Ros2Rag ros2rag
= update_definition.d ros2rag.r {: r.getUpdateDefinitionList().insertChild(d, 0); return r; :}
| dependency_definition.d ros2rag.r {: r.getDependencyDefinitionList().insertChild(d, 0); return r; :}
| mapping_definition.d ros2rag.r {: r.getMappingDefinitionList().insertChild(d, 0); return r; :}
| {: return new Ros2Rag(); :}
;
// read Joint.CurrentPosition using LinkStateToIntPosition ;
// write RobotArm._AppropriateSpeed using CreateSpeedMessage ;
UpdateDefinition update_definition
= READ ID.type_name DOT ID.token_name SCOL
{:
ReadFromMqttDefinition result = new ReadFromMqttDefinition();
result.setToken(TokenComponent.createRef(type_name + "." + token_name));
return result;
:}
| READ ID.type_name DOT ID.token_name USING ID.mapping_def SCOL
{:
ReadFromMqttDefinition result = new ReadFromMqttDefinition();
result.setToken(TokenComponent.createRef(type_name + "." + token_name));
result.setMapping(MappingDefinition.createRef(mapping_def));
return result;
:}
| WRITE ID.type_name DOT ID.token_name SCOL
{:
WriteToMqttDefinition result = new WriteToMqttDefinition();
result.setToken(TokenComponent.createRef(type_name + "." + token_name));
return result;
:}
| WRITE ID.type_name DOT ID.token_name USING ID.mapping_def SCOL
{:
WriteToMqttDefinition result = new WriteToMqttDefinition();
result.setToken(TokenComponent.createRef(type_name + "." + token_name));
result.setMapping(MappingDefinition.createRef(mapping_def));
return result;
:}
;
// RobotArm._AppropriateSpeed canDependOn Joint.CurrentPosition as dependency1 ;
DependencyDefinition dependency_definition
= ID.target_type DOT ID.target_token CAN_DEPEND_ON ID.source_type DOT ID.source_token AS ID.id SCOL
{:
DependencyDefinition result = new DependencyDefinition();
result.setSource(TokenComponent.createRef(source_type + "." + source_token));
result.setTarget(TokenComponent.createRef(target_type + "." + target_token));
result.setID(id);
return result;
:}
;
//LinkStateToIntPosition maps protobuf panda.Linkstate.PandaLinkState x to IntPosition y {
// panda.Linkstate.PandaLinkState.Position p = x.getPos();
// y = IntPosition.of((int) p.getPositionX(), (int) p.getPositionY(), (int) p.getPositionZ());
//}
MappingDefinition mapping_definition
= ID.id MAPS java_type_use.from_type ID.from_variable TO java_type_use.to_type ID.to_variable LB_CURLY mapping_def_content.content RB_CURLY
{:
MappingDefinition result = new MappingDefinition();
result.setID(id);
result.setFrom(from_type);
result.setFromVariable(from_variable);
result.setTo(to_type);
result.setToVariable(to_variable);
result.setContent(content);
return result;
:}
;
String mapping_def_content = ID ;
Ros2Rag ::= MappingDefinition* SyncDefinition* Program; Ros2Rag ::= UpdateDefinition* DependencyDefinition* MappingDefinition* Program;
abstract SyncDefinition ::= <AlwaysApply:Boolean> ; abstract UpdateDefinition ::= <AlwaysApply:Boolean> ;
rel SyncDefinition.Mapping? -> MappingDefinition; rel UpdateDefinition.Mapping? -> MappingDefinition;
abstract TokenSyncDefinition : SyncDefinition; abstract TokenUpdateDefinition : UpdateDefinition;
rel TokenSyncDefinition.token -> TokenComponent; rel TokenUpdateDefinition.Token -> TokenComponent;
ReadFromMqttDefinition : TokenSyncDefinition; ReadFromMqttDefinition : TokenUpdateDefinition;
WriteToMqttDefinition : TokenSyncDefinition; WriteToMqttDefinition : TokenUpdateDefinition;
MappingDefinition ::= <ID> From:JavaTypeUse To:JavaTypeUse <Content> ; // example: RobotArm._AppropriateSpeed canDependOn Joint.CurrentPosition as dependency1
DependencyDefinition ::= <ID> ;
rel DependencyDefinition.Source -> TokenComponent ;
rel DependencyDefinition.Target -> TokenComponent ;
MappingDefinition ::= <ID> From:JavaTypeUse <FromVariable> To:JavaTypeUse <ToVariable> <Content> ;
...@@ -31,14 +31,14 @@ aspect Aspect { ...@@ -31,14 +31,14 @@ aspect Aspect {
public void Ros2Rag.generateAspect(StringBuilder sb) { public void Ros2Rag.generateAspect(StringBuilder sb) {
sb.append("aspect ROS2RAG {\n"); sb.append("aspect ROS2RAG {\n");
for (SyncDefinition def : getSyncDefinitionList()) { for (UpdateDefinition def : getUpdateDefinitionList()) {
def.generateAspect(sb); def.generateAspect(sb);
} }
sb.append("}\n"); sb.append("}\n");
} }
abstract void SyncDefinition.generateAspect(StringBuilder sb); abstract void UpdateDefinition.generateAspect(StringBuilder sb);
// @Override // @Override
// void UpdateDefinition.generateAspect(StringBuilder sb) { // void UpdateDefinition.generateAspect(StringBuilder sb) {
// // TODO // // TODO
......
...@@ -10,12 +10,16 @@ import org.jastadd.ros2rag.parser.RelAstParser; ...@@ -10,12 +10,16 @@ import org.jastadd.ros2rag.parser.RelAstParser;
import org.jastadd.ros2rag.scanner.RelAstScanner; import org.jastadd.ros2rag.scanner.RelAstScanner;
import java.io.*; import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class Compiler { public class Compiler {
private StringOption optionOutputDir; private StringOption optionOutputDir;
private StringOption optionInputGrammar;
private StringOption optionInputRos2Rag;
private ArrayList<Option<?>> options; private ArrayList<Option<?>> options;
private CommandLine commandLine; private CommandLine commandLine;
...@@ -31,21 +35,28 @@ public class Compiler { ...@@ -31,21 +35,28 @@ public class Compiler {
if (optionOutputDir.isSet()) { if (optionOutputDir.isSet()) {
outputDir = optionOutputDir.getValue(); outputDir = optionOutputDir.getValue();
} else { } else {
System.out.println("No output grammar name is set. Assuming output dir '" + outputDir + "'."); System.out.println("No output output dir is set. Assuming '" + outputDir + "'.");
} }
printMessage("Running ROS2RAG Preprocessor"); printMessage("Running ROS2RAG Preprocessor");
if (commandLine.getArguments().size() < 1) { if (!optionInputGrammar.isSet()) {
error("specify at least one input file"); error("specify an input grammar");
} }
List<String> filenames = commandLine.getArguments(); if (!optionInputRos2Rag.isSet()) {
Program p = parseProgram(filenames); error("specify the ros2rag definition file");
}
writeToFile(outputDir + "/Grammar.ast", p.generateAbstractGrammar()); List<String> otherArgs = commandLine.getArguments();
writeToFile(outputDir + "/ROS2RAG.jadd", p.generateAspect()); if (!otherArgs.isEmpty()) {
printMessage("Superfluous arguments will be ignored: " + otherArgs);
}
Ros2Rag ros2Rag = parseProgram(optionInputGrammar.getValue(), optionInputRos2Rag.getValue());
printMessage("Writing output files");
writeToFile(outputDir + "/Grammar.relast", ros2Rag.getProgram().generateAbstractGrammar());
writeToFile(outputDir + "/ROS2RAG.jadd", ros2Rag.generateAspect());
} }
...@@ -75,6 +86,8 @@ public class Compiler { ...@@ -75,6 +86,8 @@ public class Compiler {
private void addOptions() { private void addOptions() {
optionOutputDir = addOption(new StringOption("outputDir", "target directory for the generated files.")); optionOutputDir = addOption(new StringOption("outputDir", "target directory for the generated files."));
optionInputGrammar = addOption(new StringOption("inputGrammar", "base grammar."));
optionInputRos2Rag = addOption(new StringOption("inputRos2Rag", "ros2rag definition file."));
} }
private <OptionType extends Option<?>> OptionType addOption(OptionType option) { private <OptionType extends Option<?>> OptionType addOption(OptionType option) {
...@@ -82,23 +95,32 @@ public class Compiler { ...@@ -82,23 +95,32 @@ public class Compiler {
return option; return option;
} }
private Program parseProgram(List<String> fileNames) { private Ros2Rag parseProgram(String inputGrammarFileName, String inputRos2RagFileName) {
Program program = new Program(); Program program = new Program();
Ros2Rag ros2Rag;
for (String fileName : fileNames) { try (BufferedReader reader = Files.newBufferedReader(Paths.get(inputGrammarFileName))) {
FileReader reader = null; RelAstScanner scanner = new RelAstScanner(reader);
try { RelAstParser parser = new RelAstParser();
reader = new FileReader(fileName); GrammarFile inputGrammar = (GrammarFile) parser.parse(scanner);
} catch (FileNotFoundException e) { program.addGrammarFile(inputGrammar);
} catch (IOException | Parser.Exception e) {
System.err.println(e.getMessage()); System.err.println(e.getMessage());
System.exit(1); System.exit(1);
} }
parse(program, reader, fileName); try (BufferedReader reader = Files.newBufferedReader(Paths.get(inputRos2RagFileName))) {
RelAstScanner scanner = new RelAstScanner(reader);
RelAstParser parser = new RelAstParser();
ros2Rag = (Ros2Rag) parser.parse(scanner, RelAstParser.AltGoals.ros2rag);
ros2Rag.setProgram(program);
} catch (IOException | Parser.Exception e) {
System.err.println(e.getMessage());
System.exit(2);
return null; // poor compiler does not know System.exit()
} }
program.treeResolveAll();
return program; return ros2Rag;
} }
private void parse(Program program, Reader reader, String file) { private void parse(Program program, Reader reader, String file) {
......
...@@ -64,7 +64,7 @@ public class SimpleMain { ...@@ -64,7 +64,7 @@ public class SimpleMain {
readFromMqttDefinition.setAlwaysApply(false); readFromMqttDefinition.setAlwaysApply(false);
readFromMqttDefinition.setToken(TokenComponent.createRef("Joint.CurrentPosition")); readFromMqttDefinition.setToken(TokenComponent.createRef("Joint.CurrentPosition"));
readFromMqttDefinition.setMapping(mappingDefinition); readFromMqttDefinition.setMapping(mappingDefinition);
model.addSyncDefinition(readFromMqttDefinition); model.addUpdateDefinition(readFromMqttDefinition);
model.treeResolveAll(); model.treeResolveAll();
......
...@@ -11,10 +11,10 @@ import static org.junit.jupiter.api.Assertions.assertTrue; ...@@ -11,10 +11,10 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
public class RosToRagTest { public class RosToRagTest {
void transform(String inputFile, String outputDir) throws CommandLine.CommandLineException { void transform(String inputGrammar, String inputRos2Rag, String outputDir) throws CommandLine.CommandLineException {
System.out.println(Paths.get(".").toAbsolutePath()); System.out.println(Paths.get(".").toAbsolutePath());
assertTrue(Paths.get(inputFile).toFile().exists(), "input file does not exist"); assertTrue(Paths.get(inputGrammar).toFile().exists(), "input grammar does not exist");
File outputDirFile = Paths.get(outputDir).toFile(); File outputDirFile = Paths.get(outputDir).toFile();
if (outputDirFile.exists()) { if (outputDirFile.exists()) {
...@@ -28,7 +28,8 @@ public class RosToRagTest { ...@@ -28,7 +28,8 @@ public class RosToRagTest {
String[] args = { String[] args = {
"--outputDir=" + outputDir, "--outputDir=" + outputDir,
inputFile "--inputGrammar=" + inputGrammar,
"--inputRos2Rag=" + inputRos2Rag
}; };
new Compiler(args); new Compiler(args);
...@@ -36,6 +37,8 @@ public class RosToRagTest { ...@@ -36,6 +37,8 @@ public class RosToRagTest {
@Test @Test
void transformMinimalExample() throws CommandLine.CommandLineException { void transformMinimalExample() throws CommandLine.CommandLineException {
transform("src/test/resources/MinimalExample.relast", "src/test/resources/out"); transform("src/test/resources/Example.relast",
"src/test/resources/Example.ros2rag",
"src/test/resources/out");
} }
} }
aspect GrammarTypes {
public class IntPosition {
private final int x, y, z;
private IntPosition(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
public static IntPosition of(int x, int y, int z) {
return new IntPosition(x, y, z);
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getZ() {
return z;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
IntPosition that = (IntPosition) o;
return x == that.x &&
y == that.y &&
z == that.z;
}
@Override
public int hashCode() {
return java.util.Objects.hash(x, y, z);
}
@Override
public String toString() {
return "(" + x + ", " + y + ", " + z + ")";
}
}
}
Model ::= RobotArm ZoneModel ;
ZoneModel ::= <Size:IntPosition> SafetyZone:Zone* ;
Zone ::= Coordinate* ;
RobotArm ::= Joint* EndEffector <_AttributeTestSource:int> /<_AppropriateSpeed:double>/ ; // normally this would be: <AttributeTestSource:int> ;
Joint ::= <Name> <_CurrentPosition:IntPosition> ; // normally this would be: <CurrentPosition:IntPosition>
EndEffector : Joint;
Coordinate ::= <Position:IntPosition> ;
/* Version 2020-04-17 */
// --- update definitions ---
read Joint.CurrentPosition using LinkStateToIntPosition ;
write RobotArm._AppropriateSpeed using CreateSpeedMessage ;
// --- dependency definitions ---
RobotArm._AppropriateSpeed canDependOn Joint.CurrentPosition as dependency1 ;
RobotArm._AppropriateSpeed canDependOn RobotArm._AttributeTestSource as dependency2 ;
// --- mapping definitions ---
LinkStateToIntPosition: map protobuf panda.Linkstate.PandaLinkState x to IntPosition y {
panda.Linkstate.PandaLinkState.Position p = x.getPos();
y = IntPosition.of((int) p.getPositionX(), (int) p.getPositionY(), (int) p.getPositionZ());
}
CreateSpeedMessage: map double x to protobuf config.Robotconfig.RobotConfig y {
y = config.Robotconfig.RobotConfig.newBuilder()
.setSpeed(x)
.build();
}
Model ::= RobotArm ZoneModel ;
ZoneModel ::= Size:Position SafetyZone:Zone*;
Zone ::= Position*;
RobotArm ::= Joint* EndEffector /<ShouldUseLowSpeed:Boolean>/ ;
Joint ::= <Name> ;
rel Joint.CurrentPosition -> Position ;
EndEffector : Joint;
Position ::= <x:int> <y:int> <z:int> ;
...@@ -10,12 +10,12 @@ RobotArm._AppropriateSpeed canDependOn Joint.CurrentPosition as dependency1 ; ...@@ -10,12 +10,12 @@ RobotArm._AppropriateSpeed canDependOn Joint.CurrentPosition as dependency1 ;
RobotArm._AppropriateSpeed canDependOn RobotArm._AttributeTestSource as dependency2 ; RobotArm._AppropriateSpeed canDependOn RobotArm._AttributeTestSource as dependency2 ;
// --- mapping definitions --- // --- mapping definitions ---
LinkStateToIntPosition: map protobuf panda.Linkstate.PandaLinkState x to IntPosition y { LinkStateToIntPosition maps protobuf panda.Linkstate.PandaLinkState x to IntPosition y {
panda.Linkstate.PandaLinkState.Position p = x.getPos(); panda.Linkstate.PandaLinkState.Position p = x.getPos();
y = IntPosition.of((int) p.getPositionX(), (int) p.getPositionY(), (int) p.getPositionZ()); y = IntPosition.of((int) p.getPositionX(), (int) p.getPositionY(), (int) p.getPositionZ());
} }
CreateSpeedMessage: map double x to protobuf config.Robotconfig.RobotConfig y { CreateSpeedMessage maps double x to protobuf config.Robotconfig.RobotConfig y {
y = config.Robotconfig.RobotConfig.newBuilder() y = config.Robotconfig.RobotConfig.newBuilder()
.setSpeed(x) .setSpeed(x)
.build(); .build();
......
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