Commit 396455c9 authored by René Schöne's avatar René Schöne
Browse files

Included some error messages.

parent 2b58276b
Pipeline #6931 failed with stage
in 2 minutes and 49 seconds
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;
}
......@@ -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;
......
......@@ -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;
......
Ros2Rag ::= UpdateDefinition* DependencyDefinition* MappingDefinition* Program;
Ros2Rag ::= UpdateDefinition* DependencyDefinition* MappingDefinition* Program <FileName> ;
abstract UpdateDefinition ::= <AlwaysApply:boolean> ;
......
......@@ -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");
}
......
......@@ -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() {
......
......@@ -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);
}
......
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;
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.
*
......@@ -23,4 +29,33 @@ public class TestUtils {
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);
}
}
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