diff --git a/buildSrc b/buildSrc deleted file mode 120000 index 82284049c054b0b6ea5abcbf181c7931a1400a63..0000000000000000000000000000000000000000 --- a/buildSrc +++ /dev/null @@ -1 +0,0 @@ -relast.preprocessor/buildSrc/ \ No newline at end of file diff --git a/buildSrc/.gitignore b/buildSrc/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..567609b1234a9b8806c5a05da6c866e480aa148d --- /dev/null +++ b/buildSrc/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/buildSrc/src/main/java/org/jastadd/relast/plugin/CompilerLocationExtension.java b/buildSrc/src/main/java/org/jastadd/relast/plugin/CompilerLocationExtension.java new file mode 100644 index 0000000000000000000000000000000000000000..7580e2dfa3277a07272a6b0adc94996da5db5ba6 --- /dev/null +++ b/buildSrc/src/main/java/org/jastadd/relast/plugin/CompilerLocationExtension.java @@ -0,0 +1,21 @@ +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; + } +} diff --git a/buildSrc/src/main/java/org/jastadd/relast/plugin/RelastPlugin.java b/buildSrc/src/main/java/org/jastadd/relast/plugin/RelastPlugin.java new file mode 100644 index 0000000000000000000000000000000000000000..1ce9e963b27c2efdf53092a91335680e708e7509 --- /dev/null +++ b/buildSrc/src/main/java/org/jastadd/relast/plugin/RelastPlugin.java @@ -0,0 +1,39 @@ +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"); + } +} diff --git a/buildSrc/src/main/java/org/jastadd/relast/plugin/RelastTest.java b/buildSrc/src/main/java/org/jastadd/relast/plugin/RelastTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6ee91a83b3ffa3cd59605afcc73cb9e7c473aac1 --- /dev/null +++ b/buildSrc/src/main/java/org/jastadd/relast/plugin/RelastTest.java @@ -0,0 +1,264 @@ +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); + }); + }); + } + } + +} diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/org.jastadd.relast.plugin.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/org.jastadd.relast.plugin.properties new file mode 100644 index 0000000000000000000000000000000000000000..20222b8953522469ec2c0340ea3aeb5ed6294d13 --- /dev/null +++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/org.jastadd.relast.plugin.properties @@ -0,0 +1 @@ +implementation-class=org.jastadd.relast.plugin.RelastPlugin diff --git a/ros2rag.base/src/main/jastadd/Ros2Rag.relast b/ros2rag.base/src/main/jastadd/Ros2Rag.relast index 166950375f5e56e0ade642999d02cd35d46e61fe..1008207a6ceb854a1937e7a2a16ef6e22cbccc03 100644 --- a/ros2rag.base/src/main/jastadd/Ros2Rag.relast +++ b/ros2rag.base/src/main/jastadd/Ros2Rag.relast @@ -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 ; diff --git a/ros2rag.base/src/main/jastadd/backend/Generation.jadd b/ros2rag.base/src/main/jastadd/backend/Generation.jadd index c5f253f4a5a2c2d1d289512bd003927233eb790c..75be20c251f171af965eda685e00e489e3de023d 100644 --- a/ros2rag.base/src/main/jastadd/backend/Generation.jadd +++ b/ros2rag.base/src/main/jastadd/backend/Generation.jadd @@ -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("/"); + } + } +} diff --git a/ros2rag.base/src/main/java/org/jastadd/ros2rag/compiler/Compiler.java b/ros2rag.base/src/main/java/org/jastadd/ros2rag/compiler/Compiler.java index a4f5bdc7f53251fecbd0aaf86d98faf017684259..7cd97a36113ca9af2566321f77b59e929f70b0cd 100644 --- a/ros2rag.base/src/main/java/org/jastadd/ros2rag/compiler/Compiler.java +++ b/ros2rag.base/src/main/java/org/jastadd/ros2rag/compiler/Compiler.java @@ -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; } diff --git a/ros2rag.base/src/main/resources/MqttUpdater.jadd b/ros2rag.base/src/main/resources/MqttUpdater.jadd index 53fa6cf5dacd874382416d2855eca9cbef225cd5..ef3e483fc80a389f4d5311cbfc6b9c0dccab7885 100644 --- a/ros2rag.base/src/main/resources/MqttUpdater.jadd +++ b/ros2rag.base/src/main/resources/MqttUpdater.jadd @@ -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) { diff --git a/ros2rag.tests/.gitignore b/ros2rag.tests/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..87b4cdd3d7c6a41502ca98703abeeb69a1d536fb --- /dev/null +++ b/ros2rag.tests/.gitignore @@ -0,0 +1,5 @@ +build +src/gen-res/ +src/gen/ +out/ +*.class diff --git a/ros2rag.tests/build.gradle b/ros2rag.tests/build.gradle index bedeb8ce63ceaaa9ebe48fbd7e8c7448a406b262..f5cf3a7c17cf525412866197429bcdcbffe963ec 100644 --- a/ros2rag.tests/build.gradle +++ b/ros2rag.tests/build.gradle @@ -1,7 +1,7 @@ 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' diff --git a/ros2rag.tests/src/test/01-input/example/Example.jadd b/ros2rag.tests/src/test/01-input/example/Example.jadd index 1fd25492334984294171edab4f2e2ffae89ddc9c..40ae586a2a0feb5c4fe274cc71ba5f05da4cbaad 100644 --- a/ros2rag.tests/src/test/01-input/example/Example.jadd +++ b/ros2rag.tests/src/test/01-input/example/Example.jadd @@ -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()) { + return true; + } + } + } + return false; + } + + syn double RobotArm.getAppropriateSpeed() { + return isInSafetyZone() ? 0.4d : 1.0d; + } } diff --git a/ros2rag.tests/src/test/01-input/example/Example.relast b/ros2rag.tests/src/test/01-input/example/Example.relast index 5afeb2250283d049143a0134247fb1e374ac4296..c6b346d5df0db5b333141202a800b5951643eef2 100644 --- a/ros2rag.tests/src/test/01-input/example/Example.relast +++ b/ros2rag.tests/src/test/01-input/example/Example.relast @@ -4,9 +4,9 @@ ZoneModel ::= <Size:IntPosition> SafetyZone:Zone* ; Zone ::= Coordinate* ; -RobotArm ::= Joint* EndEffector <AttributeTestSource:int> /<AppropriateSpeed:double>/ ; // normally this would be: <AttributeTestSource:int> ; +RobotArm ::= Joint* EndEffector <AttributeTestSource:int> /<AppropriateSpeed:double>/ ; -Joint ::= <Name:String> <CurrentPosition:IntPosition> ; // normally this would be: <CurrentPosition:IntPosition> +Joint ::= <Name:String> <CurrentPosition:IntPosition> ; EndEffector : Joint; diff --git a/ros2rag.tests/src/test/java/org/jastadd/ros2rag/tests/ExampleTest.java b/ros2rag.tests/src/test/java/org/jastadd/ros2rag/tests/ExampleTest.java index 7b41810c351943775074c5fe1a0abd9e47a5afc6..9ff94b7b15bbbce1a2d2936abd53921c7b140591 100644 --- a/ros2rag.tests/src/test/java/org/jastadd/ros2rag/tests/ExampleTest.java +++ b/ros2rag.tests/src/test/java/org/jastadd/ros2rag/tests/ExampleTest.java @@ -3,6 +3,8 @@ package org.jastadd.ros2rag.tests; import example.ast.*; import org.junit.jupiter.api.Test; +import java.io.IOException; + /** * Test case "example". * @@ -11,7 +13,7 @@ import org.junit.jupiter.api.Test; public class ExampleTest { @Test - public void buildModel() { + public void buildModel() throws IOException { Model model = new Model(); model.MqttSetHost("localhost"); diff --git a/ros2rag.tests/src/test/01-input/example/linkstate.proto b/ros2rag.tests/src/test/proto/linkstate.proto similarity index 100% rename from ros2rag.tests/src/test/01-input/example/linkstate.proto rename to ros2rag.tests/src/test/proto/linkstate.proto diff --git a/ros2rag.tests/src/test/01-input/example/robotconfig.proto b/ros2rag.tests/src/test/proto/robotconfig.proto similarity index 100% rename from ros2rag.tests/src/test/01-input/example/robotconfig.proto rename to ros2rag.tests/src/test/proto/robotconfig.proto