Commit 7ed08014 authored by René Schöne's avatar René Schöne
Browse files

Step forward to working generation.

- Copied (and modified) buildSrc from relast. Added compilerLocation property to set a jar to execute.
- Completed example code with computation attributes
- Fixed various bugs in Generation.jadd
- Wrap application of mappings with try/catch and let mapping methods throw Exception
- Add grammar modification for TokenComponent used as source in dependency definition
- Add grammar extension to include relations generated by dependency definitions
- Prepare Ros2Rag.relast for default mappings (not implemented yet)
parent a882cdc3
Pipeline #6534 failed with stage
in 1 minute and 52 seconds
relast.preprocessor/buildSrc/
\ No newline at end of file
package org.jastadd.relast.plugin;
import org.gradle.api.Project;
import org.gradle.api.provider.Property;
/**
* TODO: Add description.
*
* @author rschoene - Initial contribution
*/
public class CompilerLocationExtension {
Property<String> compilerLocation;
public CompilerLocationExtension(Project project) {
compilerLocation = project.getObjects().property(String.class);
}
public Property<String> getCompilerLocation() {
return compilerLocation;
}
}
package org.jastadd.relast.plugin;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.tasks.TaskCollection;
import java.util.Set;
/**
* Plugin for RelAst-Test.
*
* @author rschoene - Initial contribution
*/
public class RelastPlugin implements Plugin<Project> {
private Task testTask;
@Override
public void apply(Project project) {
CompilerLocationExtension extension = project.getExtensions().create(
"relastTest",
CompilerLocationExtension.class,
project);
Set<Task> tasks = project.getTasksByName("test", false);
// there should be only one task "test"
testTask = tasks.iterator().next();
TaskCollection<RelastTest> relastTests = project.getTasks().withType(RelastTest.class);
relastTests.forEach(relastTest -> setupRelastTest(relastTest, extension.getCompilerLocation().getOrNull()));
relastTests.whenTaskAdded(relastTest -> setupRelastTest(relastTest, extension.getCompilerLocation().getOrNull()));
}
private void setupRelastTest(RelastTest relastTest, String compilerLocation) {
testTask.dependsOn(relastTest);
relastTest.setCompilerLocation(compilerLocation);
relastTest.setGroup("verification");
}
}
package org.jastadd.relast.plugin;
import org.gradle.api.DefaultTask;
import org.gradle.api.Project;
import org.gradle.api.file.FileCollection;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.SourceSetContainer;
import org.gradle.api.tasks.TaskAction;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* RelAst Test Task
*
* @author rschoene - Initial contribution
*/
@SuppressWarnings({"unused", "WeakerAccess"})
public class RelastTest extends DefaultTask {
// configuration from plugin
private String compilerLocation;
// general options
private boolean verbose = false;
// pre-process options
private List<String> relastFiles = new ArrayList<>();
private boolean useJastAddNames;
private boolean resolverHelper;
private boolean writeToFile = true;
private String grammarName;
private String listClass;
private String jastAddList;
private String serializer;
// compile options
private boolean runJastAdd = true;
private String outputDir = "src/test/java-gen/";
private String packageName;
private final List<String> moreInputFiles = new ArrayList<>();
public void setCompilerLocation(String compilerLocation) {
this.compilerLocation = compilerLocation;
}
public boolean isVerbose() {
return verbose;
}
public void setVerbose(boolean verbose) {
this.verbose = verbose;
}
// pre-process options
public List<String> getRelastFiles() {
return relastFiles;
}
public void relastFiles(String relastFile) {
this.relastFiles.add(relastFile);
}
public void relastFiles(String[] relastFilesArray) {
this.relastFiles = Arrays.asList(relastFilesArray);
}
public boolean isUseJastAddNames() {
return useJastAddNames;
}
public void setUseJastAddNames(boolean useJastAddNames) {
this.useJastAddNames = useJastAddNames;
}
public boolean isResolverHelper() {
return resolverHelper;
}
public void setResolverHelper(boolean resolverHelper) {
this.resolverHelper = resolverHelper;
}
public boolean isWriteToFile() {
return writeToFile;
}
public void setWriteToFile(boolean writeToFile) {
this.writeToFile = writeToFile;
}
public String getGrammarName() {
return grammarName;
}
public void setGrammarName(String grammarName) {
this.grammarName = grammarName;
}
public String getListClass() {
return listClass;
}
public void setListClass(String listClass) {
this.listClass = listClass;
}
public String getJastAddList() {
return jastAddList;
}
public void setJastAddList(String jastAddList) {
this.jastAddList = jastAddList;
}
public String getSerializer() {
return serializer;
}
public void setSerializer(String serializer) {
this.serializer = serializer;
}
// compile options
public boolean isRunJastAdd() {
return runJastAdd;
}
public void setRunJastAdd(boolean runJastAdd) {
this.runJastAdd = runJastAdd;
}
public String getOutputDir() {
return outputDir;
}
public void setOutputDir(String outputDir) {
this.outputDir = outputDir;
}
public String getPackageName() {
return packageName;
}
public void setPackageName(String packageName) {
this.packageName = packageName;
}
public List<String> getMoreInputFiles() {
return moreInputFiles;
}
public void moreInputFiles(String f) {
this.moreInputFiles.add(f);
}
public void moreInputFiles(String[] fileArray) {
this.moreInputFiles.addAll(Arrays.asList(fileArray));
}
private boolean isSet(String option) {
return option != null && !option.isEmpty();
}
private String[] genSuffixes = {".ast", ".jadd", "RefResolver.jadd", "ResolverStubs.jrag", "Serializer.jadd"};
@TaskAction
void runTest() {
setGroup("verification");
setDescription("Runs a relast test");
Project project = getProject();
if (isVerbose()) {
System.out.println("Running relast test");
System.out.println("relast files: " + getRelastFiles());
System.out.println("Deleting files");
}
// first, delete generated files
List<String> genFiles = new ArrayList<>();
for (String suffix : genSuffixes) {
genFiles.add(getGrammarName() + suffix);
}
if (isVerbose()) {
System.out.println("gen files: " + genFiles);
}
project.delete(deleteSpec -> {
deleteSpec.delete(genFiles);
if (isSet(getPackageName())) {
deleteSpec.delete(Paths.get(getOutputDir(), getPackageName()));
}
});
if (isVerbose()) {
System.out.println("Pre processing, running relast");
}
// then, run relast pre processing
project.getPlugins().withType(JavaPlugin.class, javaPlugin -> {
SourceSetContainer sourceSets = (SourceSetContainer) project.getProperties().get("sourceSets");
FileCollection runtimeClasspath = sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME).getRuntimeClasspath();
project.javaexec(javaExecSpec -> {
List<Object> args = new ArrayList<>();
javaExecSpec.setClasspath(runtimeClasspath);
if (compilerLocation != null) {
javaExecSpec.setMain("-jar");
args.add(compilerLocation);
} else {
javaExecSpec.setMain("org.jastadd.relast.compiler.Compiler");
}
args.addAll(getRelastFiles());
args.add("--quiet");
if (isWriteToFile()) {
args.add("--file");
}
if (isUseJastAddNames()) {
args.add("--useJastAddNames");
}
if (isResolverHelper()) {
args.add("--resolverHelper");
}
if (isSet(getJastAddList())) {
args.add("--jastAddList=" + getJastAddList());
}
if (isSet(getListClass())) {
args.add("--listClass=" + getListClass());
}
if (isSet(getSerializer())) {
args.add("--serializer=" + getSerializer());
}
args.add("--grammarName=" + getGrammarName());
if (isVerbose()) {
System.out.println("Start relast with args: " + args);
}
javaExecSpec.args(args);
});
});
if (isRunJastAdd()) {
if (isVerbose()) {
System.out.println("Compile with JastAdd");
}
// check which files were actually generated
genFiles.removeIf(s -> !Paths.get(s).toFile().exists());
// finally, compile generated files
project.getPlugins().withType(JavaPlugin.class, javaPlugin -> {
SourceSetContainer sourceSets = (SourceSetContainer) project.getProperties().get("sourceSets");
FileCollection runtimeClasspath = sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME).getRuntimeClasspath();
project.javaexec(javaExecSpec -> {
javaExecSpec.setClasspath(runtimeClasspath);
javaExecSpec.setMain("org.jastadd.JastAdd");
List<Object> args = new ArrayList<>();
args.add("--o=" + getOutputDir());
args.add("--package=" + getPackageName());
if (isSet(getJastAddList())) {
args.add("--List=" + getJastAddList());
}
args.addAll(genFiles);
args.addAll(getMoreInputFiles());
if (isVerbose()) {
System.out.println("Start JastAdd with args: " + args);
}
javaExecSpec.args(args);
});
});
}
}
}
......@@ -11,11 +11,12 @@ ReadFromMqttDefinition : TokenUpdateDefinition;
WriteToMqttDefinition : TokenUpdateDefinition;
// example: RobotArm._AppropriateSpeed canDependOn Joint.CurrentPosition as dependency1
DependencyDefinition ::= <ID> ;
rel DependencyDefinition.Source -> TokenComponent ;
rel DependencyDefinition.Target -> TokenComponent ;
DependencyDefinition ::= <ID>;
rel DependencyDefinition.Source <-> TokenComponent.DependencySourceDefinition*;
rel DependencyDefinition.Target -> TokenComponent;
MappingDefinition ::= <ID> FromType:MappingDefinitionType <FromVariableName> ToType:MappingDefinitionType <Content> ;
abstract MappingDefinitionType ::= ;
JavaMappingDefinitionType : MappingDefinitionType ::= Type:JavaTypeUse ;
JavaArrayMappingDefinitionType : MappingDefinitionType ::= Type:JavaTypeUse ;
DefaultMappingDefinition : MappingDefinition ;
......@@ -11,6 +11,8 @@ aspect GenerationUtils {
}
aspect AspectGeneration {
syn String TokenComponent.internalName() = getDependencySourceDefinitionList().isEmpty() ? externalName() : "_internal_" + getName();
syn String TokenComponent.externalName() = getName();
// naming convention attributes
syn String TokenUpdateDefinition.connectMethod() = "connect" + getToken().getName();
......@@ -24,7 +26,7 @@ aspect AspectGeneration {
Character.toUpperCase(getID().charAt(0)) +
getID().substring(1);
syn String DependencyDefinition.internalRelationPrefix() = "_internal_" + getID();
syn String DependencyDefinition.internalTokenName() = "_internal" + getSource().getName();
syn String DependencyDefinition.internalTokenName() = getSource().internalName();
inh String UpdateDefinition.mqttUpdaterAttribute();
inh String MappingDefinition.mqttUpdaterAttribute();
......@@ -66,7 +68,7 @@ aspect AspectGeneration {
sb.append(ind(1)).append("}\n\n");
// mqttWaitUntilReady
sb.append(ind(1)).append("public void ").append(rootNodeName).append(".")
sb.append(ind(1)).append("public boolean ").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");
......@@ -111,20 +113,32 @@ aspect AspectGeneration {
String initialInputVariableName) {
final String resultVariablePrefix = "result"; // we do not need "_" here, because methodName begins with one
String inputVariableName = initialInputVariableName;
// last variable need to be declared before begin of try
MappingDefinition lastDefinition = getMappingList().get(getMappingList().size() - 1);
sb.append(ind(indent)).append(lastDefinition.getToType().prettyPrint()).append(" ")
.append(resultVariablePrefix).append(lastDefinition.methodName()).append(";\n");
sb.append(ind(indent)).append("try {\n");
for (MappingDefinition mappingDefinition : getMappingList()) {
String resultVariableName = resultVariablePrefix + mappingDefinition.methodName();
sb.append(ind(indent)).append(mappingDefinition.getToType().prettyPrint()).append(" ")
.append(resultVariablePrefix).append(mappingDefinition.methodName())
sb.append(ind(indent + 1));
if (mappingDefinition != lastDefinition) {
sb.append(mappingDefinition.getToType().prettyPrint()).append(" ");
}
sb.append(resultVariablePrefix).append(mappingDefinition.methodName())
.append(" = ").append(mappingDefinition.methodName()).append("(")
.append(inputVariableName).append(");\n");
inputVariableName = resultVariableName;
}
sb.append(ind(indent)).append("} catch (Exception e) {\n");
sb.append(ind(indent + 1)).append("e.printStackTrace();\n");
sb.append(ind(indent + 1)).append(preemptiveReturnStatement()).append("\n");
sb.append(ind(indent)).append("}\n");
if (!getAlwaysApply()) {
sb.append(ind(indent)).append("if (get").append(getToken().getName()).append("()");
sb.append(ind(indent)).append("if (").append(preemptiveExpectedValue());
if (getToken().isPrimitiveType()) {
sb.append(" == ").append(inputVariableName);
} else {
sb.append(" != null ? get").append(getToken().getName()).append("().equals(")
sb.append(" != null ? ").append(preemptiveExpectedValue()).append(".equals(")
.append(inputVariableName).append(")").append(" : ")
.append(inputVariableName).append(" == null");
}
......@@ -133,6 +147,10 @@ aspect AspectGeneration {
return inputVariableName;
}
syn String TokenUpdateDefinition.preemptiveExpectedValue();
eq ReadFromMqttDefinition.preemptiveExpectedValue() = "get" + getToken().getName() + "()";
eq WriteToMqttDefinition.preemptiveExpectedValue() = lastValue();
syn String TokenUpdateDefinition.preemptiveReturnStatement();
eq ReadFromMqttDefinition.preemptiveReturnStatement() = "return;";
eq WriteToMqttDefinition.preemptiveReturnStatement() = "return false;";
......@@ -188,7 +206,8 @@ aspect AspectGeneration {
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");
.append(getFromType().prettyPrint()).append(" ").append(getFromVariableName())
.append(") throws Exception {\n");
for (String line : getContent().split("\n")) {
if (!line.trim().isEmpty()) {
sb.append(ind(2)).append(line).append("\n");
......@@ -226,7 +245,45 @@ aspect AspectGeneration {
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(2)).append("return get").append(internalTokenName()).append("();\n");
sb.append(ind(1)).append("}\n\n");
}
}
aspect RelationGeneration {
syn java.util.List<Relation> Ros2Rag.additionalRelations() {
java.util.List<Relation> result = new java.util.ArrayList<>();
for (DependencyDefinition dd : getDependencyDefinitionList()) {
result.add(dd.getRelationToCreate());
}
return result;
}
syn nta Relation DependencyDefinition.getRelationToCreate() {
BidirectionalRelation result = new BidirectionalRelation();
NavigableRole left = new ListRole(internalRelationPrefix() + "Source");
left.setType(getTarget().containingTypeDecl());
NavigableRole right = new ListRole(internalRelationPrefix() + "Target");
right.setType(getSource().containingTypeDecl());
result.setLeft(left);
result.setRight(right);
return result;
}
}
aspect GrammarExtension {
refine BackendAbstractGrammar public void TokenComponent.generateAbstractGrammar(StringBuilder b) {
if (getNTA()) {
b.append("/");
}
b.append("<");
if (!getName().equals("")) {
b.append(internalName()).append(":");
}
getJavaTypeUse().generateAbstractGrammar(b);
b.append(">");
if (getNTA()) {
b.append("/");
}
}
}
......@@ -139,11 +139,12 @@ public class Compiler {
private Ros2Rag parseProgram(String inputGrammarFileName, String inputRos2RagFileName) throws CompilerException {
Program program = new Program();
Ros2Rag ros2Rag;
GrammarFile inputGrammar;
try (BufferedReader reader = Files.newBufferedReader(Paths.get(inputGrammarFileName))) {
Ros2RagScanner scanner = new Ros2RagScanner(reader);
Ros2RagParser parser = new Ros2RagParser();
GrammarFile inputGrammar = (GrammarFile) parser.parse(scanner);
inputGrammar = (GrammarFile) parser.parse(scanner);
inputGrammar.dumpTree(System.out);
program.addGrammarFile(inputGrammar);
inputGrammar.treeResolveAll();
......@@ -159,11 +160,8 @@ public class Compiler {
} catch (IOException | Parser.Exception e) {
throw new CompilerException("Could not parse ros2rag file " + inputRos2RagFileName, e);
}
ros2Rag.dumpTree(System.out);
ros2Rag.treeResolveAll();
ros2Rag.dumpTree(System.out);
ros2Rag.additionalRelations().forEach(inputGrammar::addDeclaration);
return ros2Rag;
}
......
......@@ -144,7 +144,7 @@ public class MqttUpdater {
callbacks.put(topic, callback);
// subscribe at broker
Topic[] topicArray = { new Topic(topic, this.qos) };
org.fusesource.mqtt.client.Topic[] topicArray = { new org.fusesource.mqtt.client.Topic(topic, this.qos) };
connection.subscribe(topicArray, new org.fusesource.mqtt.client.Callback<byte[]>() {
@Override
public void onSuccess(byte[] qoses) {
......
build
src/gen-res/
src/gen/
out/
*.class
import org.jastadd.relast.plugin.RelastPlugin
import org.jastadd.relast.plugin.RelastTest
apply plugin: 'jastadd'
apply plugin: 'application'
apply plugin: 'com.google.protobuf'
apply plugin: RelastPlugin
sourceCompatibility = 1.8
......@@ -14,6 +14,7 @@ buildscript {
repositories.jcenter()
dependencies {
classpath 'org.jastadd:jastaddgradle:1.13.3'
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.12'
}
}
......@@ -44,6 +45,15 @@ sourceSets {
}
}
protobuf {
// create strange directories, so use default here
generatedFilesBaseDir = "$projectDir/src/test/java-gen/proto"
protoc {
// The artifact spec for the Protobuf Compiler
artifact = 'com.google.protobuf:protoc:3.0.0'
}
}
task preprocessExampleTest(type: JavaExec, group: 'verification') {
doFirst {
delete 'src/test/02-after-ros2rag/example/Grammar.relast',
......@@ -77,7 +87,7 @@ task preprocessExampleTest(type: JavaExec, group: 'verification') {
//}
task compileExampleTest(type: RelastTest) {
verbose = true
useJastAddNames = true
relastFiles 'src/test/02-after-ros2rag/example/Grammar.relast'
grammarName = 'src/test/03-after-relast/example/example'
packageName = 'example.ast'
......
......@@ -44,4 +44,42 @@ aspect GrammarTypes {
return "(" + x + ", " + y + ", " + z + ")";
}
}
inh Model RobotArm.model();
eq Model.getRobotArm().model() = this;
inh RobotArm Joint.containingRobotArm();
eq RobotArm.getJoint().containingRobotArm() = this;
eq RobotArm.getEndEffector().containingRobotArm() = this;
syn boolean RobotArm.isInSafetyZone() {
for (Joint joint : getJointList()) {
if (model().getZoneModel().isInSafetyZone(joint.getCurrentPosition())) {
return true;
}
}
return model().getZoneModel().isInSafetyZone(getEndEffector().getCurrentPosition());
}
cache ZoneModel.isInSafetyZone(IntPosition pos);
syn boolean ZoneModel.isInSafetyZone(IntPosition pos) {
for (Zone sz : getSafetyZoneList()) {
for (Coordinate coordinate : sz.getCoordinateList()) {
IntPosition inside = coordinate.getPosition();
if (inside.getX() <= pos.getX() &&
inside.getY() <= pos.getY() &&
inside.getZ() <= pos.getZ() &&
pos.getX() <= inside.getX() + getSize().getX() &&
pos.getY() <= inside.getY() + getSize().getY() &&
pos.getZ() <= inside.getZ() + getSize().getZ()) {