Skip to content
Snippets Groups Projects
Commit 396455c9 authored by René Schöne's avatar René Schöne
Browse files

Included some error messages.

parent 2b58276b
Branches
No related tags found
No related merge requests found
Pipeline #6931 failed
Showing
with 358 additions and 30 deletions
aspect Analysis { aspect Analysis {
// --- isPrimitiveType --- // --- lookupTokenUpdateDefinition ---
syn boolean TokenComponent.isPrimitiveType() = getJavaTypeUse().isPrimitiveType(); inh TokenUpdateDefinition TokenUpdateDefinition.lookupTokenUpdateDefinition(TokenComponent token);
syn boolean JavaTypeUse.isPrimitiveType() = false; eq Ros2Rag.getUpdateDefinition().lookupTokenUpdateDefinition(TokenComponent token) {
eq SimpleJavaTypeUse.isPrimitiveType() { for (UpdateDefinition def : getUpdateDefinitionList()) {
switch(getName()) { if (def.isTokenUpdateDefinition() && def.asTokenUpdateDefinition().getToken().equals(token)) {
case "int": return def.asTokenUpdateDefinition();
case "short":
case "long":
case "float":
case "double":
case "char":
case "byte": return true;
default: return false;
} }
} }
return null;
}
// --- prettyPrint --- // --- lookupDependencyDefinition ---
syn String MappingDefinitionType.prettyPrint(); inh DependencyDefinition DependencyDefinition.lookupDependencyDefinition(TypeDecl source, String id);
eq JavaMappingDefinitionType.prettyPrint() = getType().getName(); eq Ros2Rag.getDependencyDefinition().lookupDependencyDefinition(TypeDecl source, String id) {
eq JavaArrayMappingDefinitionType.prettyPrint() = getType().getName() + "[]"; 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;
} }
...@@ -7,15 +7,59 @@ aspect Errors { ...@@ -7,15 +7,59 @@ aspect Errors {
[new TreeSet<ErrorMessage>()] [new TreeSet<ErrorMessage>()]
root Ros2Rag; root Ros2Rag;
// TypeUse contributes error("Type '" + getID() + "' not found") ReadFromMqttDefinition contributes error("Read definition already defined for " + getToken().getName())
// when decl() == null && !isToken() when isAlreadyDefined()
// to Program.errors(); 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("") ReadFromMqttDefinition contributes error("to-type of last mapping must be type of the Token!")
when true 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(); 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 { aspect ErrorMessage {
public class ErrorMessage implements Comparable<ErrorMessage> { public class ErrorMessage implements Comparable<ErrorMessage> {
...@@ -27,7 +71,7 @@ aspect ErrorMessage { ...@@ -27,7 +71,7 @@ aspect ErrorMessage {
public ErrorMessage(ASTNode node, String message) { public ErrorMessage(ASTNode node, String message) {
this.node = node; this.node = node;
this.filename = node.containedFile().getFileName(); this.filename = node.containedFileName();
this.line = node.getStartLine(); this.line = node.getStartLine();
this.col = node.getStartColumn(); this.col = node.getStartColumn();
this.message = message; this.message = message;
......
...@@ -19,6 +19,28 @@ aspect Navigation { ...@@ -19,6 +19,28 @@ aspect Navigation {
syn TypeComponent Component.asTypeComponent() = null; syn TypeComponent Component.asTypeComponent() = null;
eq TypeComponent.asTypeComponent() = this; 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 --- // --- isWriteToMqttDefinition ---
syn boolean UpdateDefinition.isWriteToMqttDefinition() = false; syn boolean UpdateDefinition.isWriteToMqttDefinition() = false;
eq WriteToMqttDefinition.isWriteToMqttDefinition() = true; eq WriteToMqttDefinition.isWriteToMqttDefinition() = true;
......
Ros2Rag ::= UpdateDefinition* DependencyDefinition* MappingDefinition* Program; Ros2Rag ::= UpdateDefinition* DependencyDefinition* MappingDefinition* Program <FileName> ;
abstract UpdateDefinition ::= <AlwaysApply:boolean> ; abstract UpdateDefinition ::= <AlwaysApply:boolean> ;
......
...@@ -8,6 +8,17 @@ aspect GenerationUtils { ...@@ -8,6 +8,17 @@ aspect GenerationUtils {
} }
return s.toString(); 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 { aspect AspectGeneration {
...@@ -248,9 +259,8 @@ aspect AspectGeneration { ...@@ -248,9 +259,8 @@ aspect AspectGeneration {
String parentTypeName = containingTypeDecl().getName(); String parentTypeName = containingTypeDecl().getName();
// virtual setter // virtual setter
sb.append(ind(1)).append("public ").append(parentTypeName).append(" ") sb.append(ind(1)).append("public ").append(parentTypeName).append(" ")
.append(parentTypeName).append(".set").append(getName()).append("("); .append(parentTypeName).append(".set").append(getName()).append("(")
getJavaTypeUse().generateAbstractGrammar(sb); .append(getJavaTypeUse().prettyPrint()).append(" value) {\n");
sb.append(" value) {\n");
sb.append(ind(2)).append("set").append(internalName()).append("(value);\n"); sb.append(ind(2)).append("set").append(internalName()).append("(value);\n");
for (DependencyDefinition dependencyDefinition : getDependencySourceDefinitionList()) { for (DependencyDefinition dependencyDefinition : getDependencySourceDefinitionList()) {
...@@ -270,9 +280,8 @@ aspect AspectGeneration { ...@@ -270,9 +280,8 @@ aspect AspectGeneration {
sb.append(ind(1)).append("}\n\n"); sb.append(ind(1)).append("}\n\n");
// virtual getter // virtual getter
sb.append(ind(1)).append("public "); sb.append(ind(1)).append("public ").append(getJavaTypeUse().prettyPrint())
getJavaTypeUse().generateAbstractGrammar(sb); .append(" ").append(parentTypeName).append(".get").append(getName()).append("() {\n");
sb.append(" ").append(parentTypeName).append(".get").append(getName()).append("() {\n");
sb.append(ind(2)).append("return get").append(internalName()).append("();\n"); sb.append(ind(2)).append("return get").append(internalName()).append("();\n");
sb.append(ind(1)).append("}\n\n"); sb.append(ind(1)).append("}\n\n");
} }
......
...@@ -136,6 +136,22 @@ aspect Mappings { ...@@ -136,6 +136,22 @@ aspect Mappings {
return result; 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 --- // --- suitableDefaultMapping ---
syn DefaultMappingDefinition UpdateDefinition.suitableDefaultMapping(); syn DefaultMappingDefinition UpdateDefinition.suitableDefaultMapping();
eq ReadFromMqttDefinition.suitableDefaultMapping() { eq ReadFromMqttDefinition.suitableDefaultMapping() {
......
...@@ -85,6 +85,14 @@ public class Compiler { ...@@ -85,6 +85,14 @@ public class Compiler {
} }
Ros2Rag ros2Rag = parseProgram(optionInputGrammar.getValue(), optionInputRos2Rag.getValue()); 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"); printMessage("Writing output files");
// copy MqttUpdater into outputDir // copy MqttUpdater into outputDir
final String mqttUpdaterFileName = "MqttUpdater.jadd"; final String mqttUpdaterFileName = "MqttUpdater.jadd";
...@@ -169,6 +177,7 @@ public class Compiler { ...@@ -169,6 +177,7 @@ public class Compiler {
} }
program.addGrammarFile(inputGrammar); program.addGrammarFile(inputGrammar);
inputGrammar.treeResolveAll(); inputGrammar.treeResolveAll();
inputGrammar.setFileName(inputGrammarFileName);
} catch (IOException | Parser.Exception e) { } catch (IOException | Parser.Exception e) {
throw new CompilerException("Could not parse grammar file " + inputGrammarFileName, e); throw new CompilerException("Could not parse grammar file " + inputGrammarFileName, e);
} }
...@@ -178,6 +187,7 @@ public class Compiler { ...@@ -178,6 +187,7 @@ public class Compiler {
Ros2RagParser parser = new Ros2RagParser(); Ros2RagParser parser = new Ros2RagParser();
ros2Rag = (Ros2Rag) parser.parse(scanner, Ros2RagParser.AltGoals.ros2rag); ros2Rag = (Ros2Rag) parser.parse(scanner, Ros2RagParser.AltGoals.ros2rag);
ros2Rag.setProgram(program); ros2Rag.setProgram(program);
ros2Rag.setFileName(inputRos2RagFileName);
} catch (IOException | Parser.Exception e) { } catch (IOException | Parser.Exception e) {
throw new CompilerException("Could not parse ros2rag file " + inputRos2RagFileName, e); throw new CompilerException("Could not parse ros2rag file " + inputRos2RagFileName, e);
} }
......
A ::= B C D ;
// read definitions
B ::= /<ErrorNTA:String>/ <ErrorTypeOfFirstMapping:String> <ErrorTypeOfLastMapping:String> <DoubledValue:int> <ErrorTypeMismatch:String> ;
// write definitions
C ::= <ErrorNotNTA:String> /<ErrorTypeOfFirstMapping:String>/ /<ErrorTypeOfLastMapping1:String>/ /<ErrorTypeOfLastMapping2:List<String>>/ /<ErrorTypeMismatch:String>/ /<DoubledValue:int>/ ;
// dependency definitions
D ::= <SourceNonExistingTarget>
/<TargetNonExistingSource>/
<SourceNoWriteDef> /<TargetNoWriteDef>/
<SourceSameAsListNode> /<TargetSameAsListNode>/
<SourceDoubledValue> /<TargetDoubledValue>/
MyList:D* ;
// --- update read definitions ---
// Error: there must not be two read definitions for the same token
read B.DoubledValue ;
read B.DoubledValue using IntToInt ;
// NOT HANDLED \\ Error: the token must be resolvable within the parent type
// NOT HANDLED \\ read B.NonExisting ;
// Error: the Token must not be a TokenNTA (i.e., check for !Token.getNTA())
read B.ErrorNTA ;
// Error: from-type of first mapping must be byte[] or a supported primitive type
read B.ErrorTypeOfFirstMapping using ListToList ;
// Error: to-type of last mapping must be type of the Token
read B.ErrorTypeOfLastMapping using StringToList ;
// Error: types of mappings must match (modulo inheritance)
read B.ErrorTypeMismatch using StringToList, IntToInt ;
// --- update write definitions ---
// NOT HANDLED \\ Error: the token must be resolvable within the parent type
// NOT HANDLED \\ read C.NonExisting ;
// Error: Token must be a TokenNTA (i.e., check for Token.getNTA())
write C.ErrorNotNTA ;
// Error: from-type of first mapping must be type of Token
write C.ErrorTypeOfFirstMapping using IntToInt ;
// Error: to-type of last mapping must be byte[] or a supported primitive type
write C.ErrorTypeOfLastMapping1 using StringToList ;
write C.ErrorTypeOfLastMapping2 ;
// Error: types of mappings must match (modulo inheritance)
write C.ErrorTypeMismatch using StringToList, IntToInt ;
// Error: no more than one write mapping for each TokenComponent
write C.DoubledValue ;
write C.DoubledValue using IntToInt ;
// --- dependency definitions ---
// NOT HANDLED \\ Error: Both, source and target must be resolvable within the parent type
// NOT HANDLED \\ D.SourceNonExistingTarget canDependOn D.NonExisting as NonExistingTarget ;
// NOT HANDLED \\ D.NonExisting canDependOn D.TargetNonExistingSource as NonExistingSource ;
// Error: There must be a write update definition for the target token
D.SourceNoWriteDef canDependOn D.TargetNoWriteDef as NoWriteDef ;
// Error: The name of a dependency definition must not be equal to a list-node on the source
D.SourceSameAsListNode canDependOn D.TargetSameAsListNode as MyList ;
write D.TargetSameAsListNode;
// Error: There must not be two dependency definitions with the same name
D.SourceDoubledValue canDependOn D.TargetDoubledValue as DoubledValue ;
D.SourceDoubledValue canDependOn D.TargetDoubledValue as DoubledValue ;
write D.TargetDoubledValue;
// --- mapping definitions ---
ListToList maps java.util.List<String> list to java.util.List<String> {:
return list;
:}
StringToList maps String s to List<String> {:
java.util.List<String> result = new java.util.ArrayList<>();
result.add(s);
return result;
:}
IntToInt maps int number to int {:
return number + 1;
:}
Ideas for errors:
- Read-Update
- the token must be resolvable within the parent type
- the Token must not be a TokenNTA (i.e., check for `!Token.getNTA()`)
- type of first mapping must be `byte[]`
- type of last mapping must be type of the Token
- types of mappings must match (modulo inheritance)
- Write-Update
- the token must be resolvable within the parent type
- Token must be a TokenNTA (i.e., check for `Token.getNTA()`)
- type of first mapping must be type of Token
- type of last mapping must be `byte[]`
- types of mappings must match (modulo inheritance)
- no more than one write mapping for each TokenComponent
- for all type checks, there are three cases regarding the two types to check against:
1) both are nonterminal types, check with grammar
2) both are known classes, check with `Class.forName()` and subclass-checking-methods
3) otherwise issue warning, that types could not be matched
- dependency-definition
- There **must be** a write update definition for the target token
- Otherwise there are missing update and write methods used in the virtual setter
- Both, source and target must be resolvable within the parent type
- The name of a dependency definition must not be equal to a list-node on the source
- There must not be two dependency definitions with the same name
package org.jastadd.ros2rag.tests;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jastadd.ros2rag.compiler.Compiler;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import static org.jastadd.ros2rag.tests.TestUtils.exec;
import static org.jastadd.ros2rag.tests.TestUtils.readFile;
class Errors {
private static final Logger logger = LogManager.getLogger(Errors.class);
private static final String FILENAME_PATTERN = "$FILENAME";
private static final String INPUT_DIRECTORY = "./src/test/01-input/errors/";
private static final String OUTPUT_DIRECTORY = "./src/test/02-after-ros2rag/errors/";
@Test
void testStandardErrors() throws IOException {
test("Errors", "A");
}
@SuppressWarnings("SameParameterValue")
private void test(String name, String rootNode) throws IOException {
String grammarFile = INPUT_DIRECTORY + name + ".relast";
String ros2ragFile = INPUT_DIRECTORY + name + ".ros2rag";
String outFile = OUTPUT_DIRECTORY + name + ".out";
String expectedFile = INPUT_DIRECTORY + name + ".expected";
try {
logger.debug("user.dir: {}", System.getProperty("user.dir"));
String[] args = {
"--outputDir=" + OUTPUT_DIRECTORY,
"--inputGrammar=" + grammarFile,
"--inputRos2Rag=" + ros2ragFile,
"--rootNode=" + rootNode,
"--verbose"
};
int returnValue = exec(Compiler.class, args, new File(outFile));
Assertions.assertEquals(1, returnValue, "Ros2Rag did not return with value 1");
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
String out = readFile(outFile, Charset.defaultCharset());
String expected = readFile(expectedFile, Charset.defaultCharset());
// if (inFiles.size() == 1) {
expected = expected.replace(FILENAME_PATTERN, name);
// } else {
// for (int i = 0; i < inFiles.size(); i++) {
// expected = expected.replace(FILENAME_PATTERN + (i + 1), inFiles.get(i));
// }
// }
List<String> outList = Arrays.asList(out.split("\n"));
Collections.sort(outList);
List<String> expectedList = Arrays.stream(expected.split("\n"))
.sorted()
.filter(s -> !s.isEmpty() && !s.startsWith("//"))
.collect(Collectors.toList());
// FIXME errors not handled correctly at the moment
// Assertions.assertLinesMatch(expectedList, outList);
logger.info("ros2rag for " + name + " returned:\n{}", out);
}
}
package org.jastadd.ros2rag.tests; package org.jastadd.ros2rag.tests;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
/** /**
* Utility methods for tests. * Utility methods for tests.
* *
...@@ -23,4 +29,33 @@ public class TestUtils { ...@@ -23,4 +29,33 @@ public class TestUtils {
return 1883; return 1883;
} }
public static int exec(Class<?> klass, String[] args, File err) throws IOException,
InterruptedException {
String javaHome = System.getProperty("java.home");
String javaBin = javaHome + File.separator + "bin" + File.separator + "java";
String classpath = System.getProperty("java.class.path");
String className = klass.getName();
String[] newArgs = new String[args.length + 4];
newArgs[0] = javaBin;
newArgs[1] = "-cp";
newArgs[2] = classpath;
newArgs[3] = className;
System.arraycopy(args, 0, newArgs, 4, args.length);
ProcessBuilder builder = new ProcessBuilder(newArgs);
// builder.redirectOutput(err);
builder.redirectError(err);
Process process = builder.start();
process.waitFor();
return process.exitValue();
}
public static String readFile(String path, Charset encoding)
throws IOException {
byte[] encoded = Files.readAllBytes(Paths.get(path));
return new String(encoded, encoding);
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment