diff --git a/src/main/jastadd/Analysis.jrag b/src/main/jastadd/Analysis.jrag index 6c8755e77db354ed36900f3439cd6fd8c5e6f2f5..228a3479df5be9d24998479bc3b48bd1626775aa 100644 --- a/src/main/jastadd/Analysis.jrag +++ b/src/main/jastadd/Analysis.jrag @@ -1,23 +1,27 @@ aspect Analysis { - // --- isPrimitiveType --- - syn boolean TokenComponent.isPrimitiveType() = getJavaTypeUse().isPrimitiveType(); - syn boolean JavaTypeUse.isPrimitiveType() = false; - eq SimpleJavaTypeUse.isPrimitiveType() { - switch(getName()) { - case "int": - case "short": - case "long": - case "float": - case "double": - case "char": - case "byte": return true; - default: return false; + // --- lookupTokenUpdateDefinition --- + inh TokenUpdateDefinition TokenUpdateDefinition.lookupTokenUpdateDefinition(TokenComponent token); + eq Ros2Rag.getUpdateDefinition().lookupTokenUpdateDefinition(TokenComponent token) { + for (UpdateDefinition def : getUpdateDefinitionList()) { + if (def.isTokenUpdateDefinition() && def.asTokenUpdateDefinition().getToken().equals(token)) { + return def.asTokenUpdateDefinition(); + } } + return null; } - // --- prettyPrint --- - syn String MappingDefinitionType.prettyPrint(); - eq JavaMappingDefinitionType.prettyPrint() = getType().getName(); - eq JavaArrayMappingDefinitionType.prettyPrint() = getType().getName() + "[]"; + // --- lookupDependencyDefinition --- + inh DependencyDefinition DependencyDefinition.lookupDependencyDefinition(TypeDecl source, String id); + eq Ros2Rag.getDependencyDefinition().lookupDependencyDefinition(TypeDecl source, String id) { + for (DependencyDefinition def : getDependencyDefinitionList()) { + if (def.getID().equals(id) && def.getSource().containingTypeDecl().equals(source)) { + return def; + } + } + return null; + } + // --- isAlreadyDefined --- + syn boolean TokenUpdateDefinition.isAlreadyDefined() = lookupTokenUpdateDefinition(getToken()) != this; + syn boolean DependencyDefinition.isAlreadyDefined() = lookupDependencyDefinition(getSource().containingTypeDecl(), getID()) != this; } diff --git a/src/main/jastadd/Errors.jrag b/src/main/jastadd/Errors.jrag index 7fb6b00b626a04b0d0c9eb3036242d728c64e050..ef223a4081e169273555140a35a9f8b47876109d 100644 --- a/src/main/jastadd/Errors.jrag +++ b/src/main/jastadd/Errors.jrag @@ -7,15 +7,59 @@ aspect Errors { [new TreeSet<ErrorMessage>()] root Ros2Rag; -// TypeUse contributes error("Type '" + getID() + "' not found") -// when decl() == null && !isToken() -// to Program.errors(); + ReadFromMqttDefinition contributes error("Read definition already defined for " + getToken().getName()) + when isAlreadyDefined() + to Ros2Rag.errors(); + + ReadFromMqttDefinition contributes error("Reading target token must not be an NTA token!") + when getToken().getNTA() + to Ros2Rag.errors(); + + // if first mapping is null, then suitableDefaultMapping() == null + ReadFromMqttDefinition contributes error("No suitable default mapping found for type " + + ((getMappingList().isEmpty()) + ? getToken().getJavaTypeUse().prettyPrint() + : getMappingList().get(0).getFromType().prettyPrint())) + when effectiveMappings().get(0) == null + to Ros2Rag.errors(); - UpdateDefinition contributes error("") - when true + ReadFromMqttDefinition contributes error("to-type of last mapping must be type of the Token!") + when getToken().getJavaTypeUse().prettyPrint().equals( + effectiveMappings().get(effectiveMappings().size() - 1)) + to Ros2Rag.errors(); + + WriteToMqttDefinition contributes error("Writing target token must be an NTA token!") + when !getToken().getNTA() + to Ros2Rag.errors(); + + WriteToMqttDefinition contributes error("Write definition already defined for " + getToken().getName()) + when isAlreadyDefined() + to Ros2Rag.errors(); + + DependencyDefinition contributes error("Dependency definition already defined for " + getSource().containingTypeDecl().getName() + " with name " + getID()) + when isAlreadyDefined() + to Ros2Rag.errors(); + + DependencyDefinition contributes error("The name of a dependency definition must not be equal to a list-node on the source") + when isAlreadyDefinedAsList() + to Ros2Rag.errors(); + + DependencyDefinition contributes error("There must be a write update definition targeting " + getSource().parentTypeypeAndName() + " for dependency definition " + getID()) + when targetUpdateDefinition() == null to Ros2Rag.errors(); } +aspect ErrorHelpers { + syn boolean DependencyDefinition.isAlreadyDefinedAsList() { + for (Component comp : getSource().containingTypeDecl().getComponentList()) { + if (comp.isListComponent() && comp.getName().equals(this.getID())) { + return true; + } + } + return false; + } + syn String TokenComponent.parentTypeypeAndName() = containingTypeDecl().getName() + "." + getName(); +} aspect ErrorMessage { public class ErrorMessage implements Comparable<ErrorMessage> { @@ -27,7 +71,7 @@ aspect ErrorMessage { public ErrorMessage(ASTNode node, String message) { this.node = node; - this.filename = node.containedFile().getFileName(); + this.filename = node.containedFileName(); this.line = node.getStartLine(); this.col = node.getStartColumn(); this.message = message; diff --git a/src/main/jastadd/Navigation.jrag b/src/main/jastadd/Navigation.jrag index 49b86d0e08ba75d817cf2e53255f8ae0c2ae9edf..f56d99825c376248ce8f9a2dae1388ed3898ea64 100644 --- a/src/main/jastadd/Navigation.jrag +++ b/src/main/jastadd/Navigation.jrag @@ -19,6 +19,28 @@ aspect Navigation { syn TypeComponent Component.asTypeComponent() = null; eq TypeComponent.asTypeComponent() = this; + // --- isListComponent (should be in preprocessor) --- + syn boolean Component.isListComponent() = false; + eq ListComponent.isListComponent() = true; + + // --- asListComponent (should be in preprocessor) --- + syn ListComponent Component.asListComponent() = null; + eq ListComponent.asListComponent() = this; + + // --- containedFileName (should replace containedFile in preprocessor) --- + inh String ASTNode.containedFileName(); + eq GrammarFile.getChild().containedFileName() = getFileName(); + eq Ros2Rag.getChild().containedFileName() = getFileName(); + eq Program.getChild().containedFileName() = null; + + // --- isTokenUpdateDefinition --- + syn boolean UpdateDefinition.isTokenUpdateDefinition() = false; + eq TokenUpdateDefinition.isTokenUpdateDefinition() = true; + + // --- asTokenUpdateDefinition --- + syn TokenUpdateDefinition UpdateDefinition.asTokenUpdateDefinition() = null; + eq TokenUpdateDefinition.asTokenUpdateDefinition() = this; + // --- isWriteToMqttDefinition --- syn boolean UpdateDefinition.isWriteToMqttDefinition() = false; eq WriteToMqttDefinition.isWriteToMqttDefinition() = true; diff --git a/src/main/jastadd/Ros2Rag.relast b/src/main/jastadd/Ros2Rag.relast index 1008207a6ceb854a1937e7a2a16ef6e22cbccc03..a5499702f44facd5b649a811a958b890d4565d0a 100644 --- a/src/main/jastadd/Ros2Rag.relast +++ b/src/main/jastadd/Ros2Rag.relast @@ -1,4 +1,4 @@ -Ros2Rag ::= UpdateDefinition* DependencyDefinition* MappingDefinition* Program; +Ros2Rag ::= UpdateDefinition* DependencyDefinition* MappingDefinition* Program <FileName> ; abstract UpdateDefinition ::= <AlwaysApply:boolean> ; diff --git a/src/main/jastadd/backend/Generation.jadd b/src/main/jastadd/backend/Generation.jadd index 7e1f988c2150a3970e53a6e36f7e22f1bd3ebc96..e698e405ee6d392d2405b15fe0869432b9b18a59 100644 --- a/src/main/jastadd/backend/Generation.jadd +++ b/src/main/jastadd/backend/Generation.jadd @@ -8,6 +8,17 @@ aspect GenerationUtils { } return s.toString(); } + + // --- prettyPrint --- + syn String MappingDefinitionType.prettyPrint(); + eq JavaMappingDefinitionType.prettyPrint() = getType().getName(); + eq JavaArrayMappingDefinitionType.prettyPrint() = getType().getName() + "[]"; + + syn String JavaTypeUse.prettyPrint() { + StringBuilder sb = new StringBuilder(); + generateAbstractGrammar(sb); + return sb.toString(); + } } aspect AspectGeneration { @@ -248,9 +259,8 @@ aspect AspectGeneration { String parentTypeName = containingTypeDecl().getName(); // virtual setter sb.append(ind(1)).append("public ").append(parentTypeName).append(" ") - .append(parentTypeName).append(".set").append(getName()).append("("); - getJavaTypeUse().generateAbstractGrammar(sb); - sb.append(" value) {\n"); + .append(parentTypeName).append(".set").append(getName()).append("(") + .append(getJavaTypeUse().prettyPrint()).append(" value) {\n"); sb.append(ind(2)).append("set").append(internalName()).append("(value);\n"); for (DependencyDefinition dependencyDefinition : getDependencySourceDefinitionList()) { @@ -270,9 +280,8 @@ aspect AspectGeneration { sb.append(ind(1)).append("}\n\n"); // virtual getter - sb.append(ind(1)).append("public "); - getJavaTypeUse().generateAbstractGrammar(sb); - sb.append(" ").append(parentTypeName).append(".get").append(getName()).append("() {\n"); + sb.append(ind(1)).append("public ").append(getJavaTypeUse().prettyPrint()) + .append(" ").append(parentTypeName).append(".get").append(getName()).append("() {\n"); sb.append(ind(2)).append("return get").append(internalName()).append("();\n"); sb.append(ind(1)).append("}\n\n"); } diff --git a/src/main/jastadd/backend/Mappings.jrag b/src/main/jastadd/backend/Mappings.jrag index 4bfe070a81b49e63996ba8f9a32a43eb13af6d1f..7add42fa7e3d3f7c71cb35b5a34c8c5d05b83628 100644 --- a/src/main/jastadd/backend/Mappings.jrag +++ b/src/main/jastadd/backend/Mappings.jrag @@ -136,6 +136,22 @@ aspect Mappings { return result; } + // --- isPrimitiveType --- + syn boolean TokenComponent.isPrimitiveType() = getJavaTypeUse().isPrimitiveType(); + syn boolean JavaTypeUse.isPrimitiveType() = false; + eq SimpleJavaTypeUse.isPrimitiveType() { + switch(getName()) { + case "int": + case "short": + case "long": + case "float": + case "double": + case "char": + case "byte": return true; + default: return false; + } + } + // --- suitableDefaultMapping --- syn DefaultMappingDefinition UpdateDefinition.suitableDefaultMapping(); eq ReadFromMqttDefinition.suitableDefaultMapping() { diff --git a/src/main/java/org/jastadd/ros2rag/compiler/Compiler.java b/src/main/java/org/jastadd/ros2rag/compiler/Compiler.java index ad4298dbd873ca42b66d85793685b78c91f01e4d..ee575b9495f53eca9925c6828ba96225734fe31a 100644 --- a/src/main/java/org/jastadd/ros2rag/compiler/Compiler.java +++ b/src/main/java/org/jastadd/ros2rag/compiler/Compiler.java @@ -85,6 +85,14 @@ public class Compiler { } Ros2Rag ros2Rag = parseProgram(optionInputGrammar.getValue(), optionInputRos2Rag.getValue()); + if (!ros2Rag.errors().isEmpty()) { + System.err.println("Errors:"); + for (ErrorMessage e : ros2Rag.errors()) { + System.err.println(e); + } + System.exit(1); + } + printMessage("Writing output files"); // copy MqttUpdater into outputDir final String mqttUpdaterFileName = "MqttUpdater.jadd"; @@ -169,6 +177,7 @@ public class Compiler { } program.addGrammarFile(inputGrammar); inputGrammar.treeResolveAll(); + inputGrammar.setFileName(inputGrammarFileName); } catch (IOException | Parser.Exception e) { throw new CompilerException("Could not parse grammar file " + inputGrammarFileName, e); } @@ -178,6 +187,7 @@ public class Compiler { Ros2RagParser parser = new Ros2RagParser(); ros2Rag = (Ros2Rag) parser.parse(scanner, Ros2RagParser.AltGoals.ros2rag); ros2Rag.setProgram(program); + ros2Rag.setFileName(inputRos2RagFileName); } catch (IOException | Parser.Exception e) { throw new CompilerException("Could not parse ros2rag file " + inputRos2RagFileName, e); }