Commit 4bf5c1ea 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 7a5db576
......@@ -109,12 +109,13 @@ jastadd {
}
scanner {
include "src/main/jastadd/RelAst.flex"
include "src/main/jastadd/Ros2Rag.flex"
}
parser {
include "src/main/jastadd/Preamble.parser"
include "src/main/jastadd/RelAst.parser"
include "src/main/jastadd/Ros2Rag.parser"
}
}
}
......
......@@ -4,3 +4,4 @@ import org.jastadd.ros2rag.ast.*;
:};
%goal goal;
%goal ros2rag;
......@@ -49,6 +49,14 @@ ID = [a-zA-Z$_][a-zA-Z0-9$_]*
"abstract" { return sym(Terminals.ABSTRACT); }
"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.COL); }
"::=" { return sym(Terminals.ASSIGN); }
......@@ -59,6 +67,8 @@ ID = [a-zA-Z$_][a-zA-Z0-9$_]*
">" { return sym(Terminals.GT); }
"[" { return sym(Terminals.LBRACKET); }
"]" { return sym(Terminals.RBRACKET); }
"{" { return sym(Terminals.LB_CURLY); }
"}" { return sym(Terminals.RB_CURLY); }
"/" { return sym(Terminals.SLASH); }
"?" { return sym(Terminals.QUESTION_MARK); }
"->" { 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;
rel TokenSyncDefinition.token -> TokenComponent;
abstract TokenUpdateDefinition : UpdateDefinition;
rel TokenUpdateDefinition.Token -> TokenComponent;
ReadFromMqttDefinition : TokenSyncDefinition;
WriteToMqttDefinition : TokenSyncDefinition;
ReadFromMqttDefinition : TokenUpdateDefinition;
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 {
public void Ros2Rag.generateAspect(StringBuilder sb) {
sb.append("aspect ROS2RAG {\n");
for (SyncDefinition def : getSyncDefinitionList()) {
for (UpdateDefinition def : getUpdateDefinitionList()) {
def.generateAspect(sb);
}
sb.append("}\n");
}
abstract void SyncDefinition.generateAspect(StringBuilder sb);
abstract void UpdateDefinition.generateAspect(StringBuilder sb);
// @Override
// void UpdateDefinition.generateAspect(StringBuilder sb) {
// // TODO
......
......@@ -10,12 +10,16 @@ import org.jastadd.ros2rag.parser.RelAstParser;
import org.jastadd.ros2rag.scanner.RelAstScanner;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
public class Compiler {
private StringOption optionOutputDir;
private StringOption optionInputGrammar;
private StringOption optionInputRos2Rag;
private ArrayList<Option<?>> options;
private CommandLine commandLine;
......@@ -31,21 +35,28 @@ public class Compiler {
if (optionOutputDir.isSet()) {
outputDir = optionOutputDir.getValue();
} 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");
if (commandLine.getArguments().size() < 1) {
error("specify at least one input file");
if (!optionInputGrammar.isSet()) {
error("specify an input grammar");
}
List<String> filenames = commandLine.getArguments();
Program p = parseProgram(filenames);
if (!optionInputRos2Rag.isSet()) {
error("specify the ros2rag definition file");
}
writeToFile(outputDir + "/Grammar.ast", p.generateAbstractGrammar());
writeToFile(outputDir + "/ROS2RAG.jadd", p.generateAspect());
List<String> otherArgs = commandLine.getArguments();
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 {
private void addOptions() {
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) {
......@@ -82,23 +95,32 @@ public class Compiler {
return option;
}
private Program parseProgram(List<String> fileNames) {
private Ros2Rag parseProgram(String inputGrammarFileName, String inputRos2RagFileName) {
Program program = new Program();
Ros2Rag ros2Rag;
try (BufferedReader reader = Files.newBufferedReader(Paths.get(inputGrammarFileName))) {
RelAstScanner scanner = new RelAstScanner(reader);
RelAstParser parser = new RelAstParser();
GrammarFile inputGrammar = (GrammarFile) parser.parse(scanner);
program.addGrammarFile(inputGrammar);
} catch (IOException | Parser.Exception e) {
System.err.println(e.getMessage());
System.exit(1);
}
for (String fileName : fileNames) {
FileReader reader = null;
try {
reader = new FileReader(fileName);
} catch (FileNotFoundException e) {
System.err.println(e.getMessage());
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) {
......
......@@ -64,7 +64,7 @@ public class SimpleMain {
readFromMqttDefinition.setAlwaysApply(false);
readFromMqttDefinition.setToken(TokenComponent.createRef("Joint.CurrentPosition"));
readFromMqttDefinition.setMapping(mappingDefinition);
model.addSyncDefinition(readFromMqttDefinition);
model.addUpdateDefinition(readFromMqttDefinition);
model.treeResolveAll();
......
......@@ -11,10 +11,10 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
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());
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();
if (outputDirFile.exists()) {
......@@ -28,7 +28,8 @@ public class RosToRagTest {
String[] args = {
"--outputDir=" + outputDir,
inputFile
"--inputGrammar=" + inputGrammar,
"--inputRos2Rag=" + inputRos2Rag
};
new Compiler(args);
......@@ -36,6 +37,8 @@ public class RosToRagTest {
@Test
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> ;
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