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

Emit filenames for error messages.

- Extended grammar to let TypeDecl and Relation have filename
- Extended error message to display and order first by filename
- Added testcase with multiple inputs having errors
parent 74ba289c
Pipeline #4240 passed with stage
in 1 minute and 16 seconds
......@@ -50,17 +50,33 @@ aspect HelpAttributes {
eq OptionalRelationComponent.multiplicityOpt() = true;
syn boolean RelationComponent.multiplicityMany() = false;
eq ManyRelationComponent.multiplicityMany() = true;
inh ContainedInFile Component.enclosingFileContainer();
eq TypeDecl.getComponent().enclosingFileContainer() = this;
eq Relation.getChild().enclosingFileContainer() = this;
inh ContainedInFile TypeUse.enclosingFileContainer();
eq SimpleTypeComponent.getTypeUse().enclosingFileContainer() = enclosingFileContainer();
eq TokenComponent.getTypeUse().enclosingFileContainer() = enclosingFileContainer();
eq TypeDecl.getSuper().enclosingFileContainer() = this;
syn String ASTNode.containedFile() = "Unknown";
eq Component.containedFile() = enclosingFileContainer() == null ? "Unknown2" : enclosingFileContainer().containedFile();
eq TypeUse.containedFile() = enclosingFileContainer() == null ? "Unknown3" : enclosingFileContainer().containedFile();
eq TypeDecl.containedFile() = getFileName();
eq Relation.containedFile() = getFileName();
}
aspect ErrorMessage {
public class ErrorMessage implements Comparable<ErrorMessage> {
private final ASTNode node;
private final String filename;
private final int line;
private final int col;
private final String message;
public ErrorMessage(ASTNode node, String message) {
this.node = node;
this.filename = node.containedFile();
this.line = node.getStartLine();
this.col = node.getStartColumn();
this.message = message;
......@@ -80,12 +96,17 @@ aspect ErrorMessage {
}
public String toString() {
return "Line " + line + ", column " + col + ": " + message;
return filename + " Line " + line + ", column " + col + ": " + message;
}
@Override
public int compareTo(ErrorMessage err) {
int n = line - err.line;
int n = filename.compareTo(err.filename);
if (n != 0) {
return n;
}
n = line - err.line;
if (n != 0) {
return n;
}
......@@ -102,4 +123,4 @@ aspect ErrorMessage {
protected ErrorMessage ASTNode.error(String message) {
return new ErrorMessage(this, message);
}
}
\ No newline at end of file
}
Program ::= TypeDecl* Relation*;
TypeDecl ::= <ID> <Abstract:boolean> [Super:TypeUse] Component*;
abstract ContainedInFile ::= <FileName> ;
TypeDecl : ContainedInFile ::= <ID> <Abstract:boolean> [Super:TypeUse] Component*;
abstract Component ::= <ID>;
abstract SimpleTypeComponent : Component ::= TypeUse:SimpleTypeUse;
......@@ -13,7 +14,7 @@ abstract TypeUse ::= <ID>;
SimpleTypeUse : TypeUse;
ParameterizedTypeUse : TypeUse ::= TypeUse*;
Relation ::= Left:RelationComponent Direction Right:RelationComponent;
Relation : ContainedInFile ::= Left:RelationComponent Direction Right:RelationComponent;
abstract RelationComponent : SimpleTypeComponent;
OneRelationComponent : RelationComponent;
OptionalRelationComponent : RelationComponent;
......
......@@ -6,9 +6,23 @@ Program goal =
TypeDecl type_decl =
ID type_decl_super.s components_opt.c SCOL
{: return new TypeDecl(ID, false, s, c); :}
{:
TypeDecl result = new TypeDecl();
result.setID(ID);
result.setAbstract(false);
result.setSuperOpt(s);
result.setComponentList(c);
return result;
:}
| ABSTRACT ID type_decl_super.s components_opt.c SCOL
{: return new TypeDecl(ID, true, s, c); :}
{:
TypeDecl result = new TypeDecl();
result.setID(ID);
result.setAbstract(true);
result.setSuperOpt(s);
result.setComponentList(c);
return result;
:}
;
Opt type_decl_super =
......@@ -21,62 +35,68 @@ SimpleTypeUse s_type_use =
;
TypeUse type_use =
s_type_use.u {: return u; :}
| parameterized_type_use.p {: return p; :}
s_type_use.u {: return u; :}
| parameterized_type_use.p {: return p; :}
;
ParameterizedTypeUse parameterized_type_use =
ID LT type_use_list.l GT {: return new ParameterizedTypeUse(ID, l); :}
ID LT type_use_list.l GT {: return new ParameterizedTypeUse(ID, l); :}
;
List type_use_list =
type_use.u {: return new List().add(u); :}
| type_use_list.l COMMA type_use.u {: return l.add(u); :}
type_use.u {: return new List().add(u); :}
| type_use_list.l COMMA type_use.u {: return l.add(u); :}
;
List components_opt =
/* empty */ {: return new List(); :}
| ASSIGN components.l {: return l; :}
/* empty */ {: return new List(); :}
| ASSIGN components.l {: return l; :}
;
List components =
{: return new List(); :}
| components.l component.c {: return l.add(c); :}
/* empty */ {: return new List(); :}
| components.l component.c {: return l.add(c); :}
;
Component component =
ID COL s_type_use.u {: return new NormalComponent(ID, u); :}
| s_type_use.u {: return new NormalComponent(u.getID(), u); :}
ID COL s_type_use.u {: return new NormalComponent(ID, u); :}
| s_type_use.u {: return new NormalComponent(u.getID(), u); :}
// List
| ID COL s_type_use.u STAR {: return new ListComponent(ID, u); :}
| s_type_use.u STAR {: return new ListComponent(u.getID(), u); :}
| ID COL s_type_use.u STAR {: return new ListComponent(ID, u); :}
| s_type_use.u STAR {: return new ListComponent(u.getID(), u); :}
// Opt
| LBRACKET ID COL s_type_use.u RBRACKET {: return new OptComponent(ID, u); :}
| LBRACKET s_type_use.u RBRACKET {: return new OptComponent(u.getID(), u); :}
| LBRACKET ID COL s_type_use.u RBRACKET {: return new OptComponent(ID, u); :}
| LBRACKET s_type_use.u RBRACKET {: return new OptComponent(u.getID(), u); :}
// NTA
| SLASH ID COL s_type_use.u SLASH {: return new NTAComponent(ID, u); :}
| SLASH s_type_use.u SLASH {: return new NTAComponent(u.getID(), u); :}
| SLASH ID COL s_type_use.u SLASH {: return new NTAComponent(ID, u); :}
| SLASH s_type_use.u SLASH {: return new NTAComponent(u.getID(), u); :}
// NTA Token (same as NTA)
| SLASH LT ID COL s_type_use.u GT SLASH {: return new NTAComponent(ID, u); :}
| SLASH LT s_type_use.u GT SLASH {: return new NTAComponent(u.getID(), u); :}
| SLASH LT ID COL s_type_use.u GT SLASH {: return new NTAComponent(ID, u); :}
| SLASH LT s_type_use.u GT SLASH {: return new NTAComponent(u.getID(), u); :}
// Token
| LT ID COL type_use.u GT {: return new TokenComponent(ID, u); :}
| LT ID GT {: return new TokenComponent(ID, new SimpleTypeUse("String")); :}
| LT ID COL type_use.u GT {: return new TokenComponent(ID, u); :}
| LT ID GT {: return new TokenComponent(ID, new SimpleTypeUse("String")); :}
;
Relation relation =
RELATION relation_comp.l direction relation_comp.r SCOL
{: return new Relation(l, direction, r); :}
{:
Relation result = new Relation();
result.setLeft(l);
result.setDirection(direction);
result.setRight(r);
return result;
:}
;
RelationComponent relation_comp =
// One
s_type_use.u DOT ID {: return new OneRelationComponent(ID, u); :}
| s_type_use.u {: return new OneRelationComponent("", u); :}
s_type_use.u DOT ID {: return new OneRelationComponent(ID, u); :}
| s_type_use.u {: return new OneRelationComponent("", u); :}
// Optional
| s_type_use.u DOT ID QUESTION_MARK {: return new OptionalRelationComponent(ID, u); :}
| s_type_use.u QUESTION_MARK {: return new OptionalRelationComponent("", u); :}
| s_type_use.u DOT ID QUESTION_MARK {: return new OptionalRelationComponent(ID, u); :}
| s_type_use.u QUESTION_MARK {: return new OptionalRelationComponent("", u); :}
// Many
| s_type_use.u DOT ID STAR {: return new ManyRelationComponent(ID, u); :}
| s_type_use.u STAR {: return new ManyRelationComponent("", u); :}
| s_type_use.u DOT ID STAR {: return new ManyRelationComponent(ID, u); :}
| s_type_use.u STAR {: return new ManyRelationComponent("", u); :}
;
Direction direction =
......
......@@ -14,7 +14,7 @@ import java.util.List;
public class Compiler {
private static final String VERSION = "0.2.1";
private static final String VERSION = "0.2.2";
private ArrayList<Option<?>> options;
private FlagOption optionWriteToFile;
......@@ -177,9 +177,11 @@ public class Compiler {
try {
Program newProgram = (Program) parser.parse(scanner);
for (TypeDecl typeDecl : newProgram.getTypeDeclList()) {
typeDecl.setFileName(file);
program.addTypeDecl(typeDecl);
}
for (Relation relation : newProgram.getRelationList()) {
relation.setFileName(file);
program.addRelation(relation);
}
} catch (IOException e) {
......
Errors:
Line 5, column 5: Role name missing for type 'A'
Line 6, column 15: Role name missing for type 'B'
Line 7, column 12: The target of a directed relation cannot have a role name
Line 8, column 13: The target of a directed relation may only have multiplicity 1
$FILENAME Line 5, column 5: Role name missing for type 'A'
$FILENAME Line 6, column 15: Role name missing for type 'B'
$FILENAME Line 7, column 12: The target of a directed relation cannot have a role name
$FILENAME Line 8, column 13: The target of a directed relation may only have multiplicity 1
Errors:
Line 2, column 12: Component 'X' is already declared for type 'B1'
Line 6, column 5: Component 'X' is already declared for type 'B2'
$FILENAME Line 2, column 12: Component 'X' is already declared for type 'B1'
$FILENAME Line 6, column 5: Component 'X' is already declared for type 'B2'
Errors:
$FILENAME1 Line 5, column 5: Role name missing for type 'A'
$FILENAME1 Line 6, column 15: Role name missing for type 'B'
$FILENAME2 Line 1, column 12: The target of a directed relation cannot have a role name
$FILENAME2 Line 2, column 13: The target of a directed relation may only have multiplicity 1
Program ::= A* B*;
A;
B;
rel A -> B;
rel A.bs* <-> B*;
rel A.b -> B.b;
rel A.b2 -> B*;
......@@ -9,6 +9,9 @@ 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.List;
import java.util.stream.Collectors;
import static org.jastadd.relast.tests.TestHelpers.exec;
import static org.jastadd.relast.tests.TestHelpers.readFile;
......@@ -17,39 +20,33 @@ import static org.jastadd.relast.tests.TestHelpers.readFile;
class Errors {
private static final Logger logger = LogManager.getLogger(Errors.class);
private static final String FILENAME_PATTERN = "$FILENAME";
@Test
void test1() throws IOException {
String inFile = "./src/test/jastadd/errors/Errors.relast";
String outFile = "./src/test/jastadd/errors/Errors.out";
String expectedFile = "./src/test/jastadd/errors/Errors.expected";
try {
System.out.println(System.getProperty("user.dir"));
int returnValue = exec(Compiler.class, new String[]{inFile}, new File(outFile));
Assertions.assertEquals(1, returnValue, "Relast did not return with value 1");
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
String out = readFile(outFile, Charset.defaultCharset());
String expected = readFile(expectedFile, Charset.defaultCharset());
Assertions.assertEquals(out, expected);
logger.info("'relast Errors.relast' returned \n{}", out);
test("Errors");
}
@Test
void test2() throws IOException {
test("Inheritance");
}
String inFile = "./src/test/jastadd/errors/Inheritance.relast";
String outFile = "./src/test/jastadd/errors/Inheritance.out";
String expectedFile = "./src/test/jastadd/errors/Inheritance.expected";
@Test
void test3() throws IOException {
test("Multiple", "Multiple_1", "Multiple_2");
}
private void test(String name, String... inFilenames) throws IOException {
List<String> inFiles = Arrays.stream(inFilenames.length > 0 ? inFilenames : new String[]{name})
.map(f -> "./src/test/jastadd/errors/" + f + ".relast")
.collect(Collectors.toList());
String outFile = "./src/test/jastadd/errors/" + name + ".out";
String expectedFile = "./src/test/jastadd/errors/" + name + ".expected";
try {
System.out.println(System.getProperty("user.dir"));
int returnValue = exec(Compiler.class, new String[]{inFile}, new File(outFile));
int returnValue = exec(Compiler.class, inFiles.toArray(new String[0]), new File(outFile));
Assertions.assertEquals(1, returnValue, "Relast did not return with value 1");
} catch (IOException | InterruptedException e) {
e.printStackTrace();
......@@ -57,10 +54,16 @@ class Errors {
String out = readFile(outFile, Charset.defaultCharset());
String expected = readFile(expectedFile, Charset.defaultCharset());
if (inFiles.size() == 1) {
expected = expected.replace(FILENAME_PATTERN, inFiles.get(0));
} else {
for (int i = 0; i < inFiles.size(); i++) {
expected = expected.replace(FILENAME_PATTERN + (i + 1), inFiles.get(i));
}
}
Assertions.assertEquals(expected, out);
Assertions.assertEquals(out, expected);
logger.info("'relast Inheritance.relast' returned \n{}", out);
logger.info("relast for " + name + " returned \n{}", out);
}
......
Supports Markdown
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