Commit c4a61a1e authored by Johannes Mey's avatar Johannes Mey
Browse files

Merge branch 'error_filenames' into 'master'

Emit filenames for error messages.

See merge request johannes.mey/relast!2
parents 74ba289c fa37120c
Pipeline #4245 passed with stage
in 58 seconds
...@@ -50,17 +50,33 @@ aspect HelpAttributes { ...@@ -50,17 +50,33 @@ aspect HelpAttributes {
eq OptionalRelationComponent.multiplicityOpt() = true; eq OptionalRelationComponent.multiplicityOpt() = true;
syn boolean RelationComponent.multiplicityMany() = false; syn boolean RelationComponent.multiplicityMany() = false;
eq ManyRelationComponent.multiplicityMany() = true; 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 { aspect ErrorMessage {
public class ErrorMessage implements Comparable<ErrorMessage> { public class ErrorMessage implements Comparable<ErrorMessage> {
private final ASTNode node; private final ASTNode node;
private final String filename;
private final int line; private final int line;
private final int col; private final int col;
private final String message; private final String message;
public ErrorMessage(ASTNode node, String message) { public ErrorMessage(ASTNode node, String message) {
this.node = node; this.node = node;
this.filename = node.containedFile();
this.line = node.getStartLine(); this.line = node.getStartLine();
this.col = node.getStartColumn(); this.col = node.getStartColumn();
this.message = message; this.message = message;
...@@ -80,12 +96,17 @@ aspect ErrorMessage { ...@@ -80,12 +96,17 @@ aspect ErrorMessage {
} }
public String toString() { public String toString() {
return "Line " + line + ", column " + col + ": " + message; return filename + " Line " + line + ", column " + col + ": " + message;
} }
@Override @Override
public int compareTo(ErrorMessage err) { 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) { if (n != 0) {
return n; return n;
} }
...@@ -102,4 +123,4 @@ aspect ErrorMessage { ...@@ -102,4 +123,4 @@ aspect ErrorMessage {
protected ErrorMessage ASTNode.error(String message) { protected ErrorMessage ASTNode.error(String message) {
return new ErrorMessage(this, message); return new ErrorMessage(this, message);
} }
} }
\ No newline at end of file
Program ::= TypeDecl* Relation*; 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 Component ::= <ID>;
abstract SimpleTypeComponent : Component ::= TypeUse:SimpleTypeUse; abstract SimpleTypeComponent : Component ::= TypeUse:SimpleTypeUse;
...@@ -13,7 +14,7 @@ abstract TypeUse ::= <ID>; ...@@ -13,7 +14,7 @@ abstract TypeUse ::= <ID>;
SimpleTypeUse : TypeUse; SimpleTypeUse : TypeUse;
ParameterizedTypeUse : TypeUse ::= TypeUse*; ParameterizedTypeUse : TypeUse ::= TypeUse*;
Relation ::= Left:RelationComponent Direction Right:RelationComponent; Relation : ContainedInFile ::= Left:RelationComponent Direction Right:RelationComponent;
abstract RelationComponent : SimpleTypeComponent; abstract RelationComponent : SimpleTypeComponent;
OneRelationComponent : RelationComponent; OneRelationComponent : RelationComponent;
OptionalRelationComponent : RelationComponent; OptionalRelationComponent : RelationComponent;
......
...@@ -6,9 +6,23 @@ Program goal = ...@@ -6,9 +6,23 @@ Program goal =
TypeDecl type_decl = TypeDecl type_decl =
ID type_decl_super.s components_opt.c SCOL 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 | 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 = Opt type_decl_super =
...@@ -21,62 +35,68 @@ SimpleTypeUse s_type_use = ...@@ -21,62 +35,68 @@ SimpleTypeUse s_type_use =
; ;
TypeUse type_use = TypeUse type_use =
s_type_use.u {: return u; :} s_type_use.u {: return u; :}
| parameterized_type_use.p {: return p; :} | parameterized_type_use.p {: return p; :}
; ;
ParameterizedTypeUse parameterized_type_use = 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 = List type_use_list =
type_use.u {: return new List().add(u); :} type_use.u {: return new List().add(u); :}
| type_use_list.l COMMA type_use.u {: return l.add(u); :} | type_use_list.l COMMA type_use.u {: return l.add(u); :}
; ;
List components_opt = List components_opt =
/* empty */ {: return new List(); :} /* empty */ {: return new List(); :}
| ASSIGN components.l {: return l; :} | ASSIGN components.l {: return l; :}
; ;
List components = List components =
{: return new List(); :} /* empty */ {: return new List(); :}
| components.l component.c {: return l.add(c); :} | components.l component.c {: return l.add(c); :}
; ;
Component component = Component component =
ID COL s_type_use.u {: return new NormalComponent(ID, u); :} ID COL s_type_use.u {: return new NormalComponent(ID, u); :}
| s_type_use.u {: return new NormalComponent(u.getID(), u); :} | s_type_use.u {: return new NormalComponent(u.getID(), u); :}
// List // List
| ID COL s_type_use.u STAR {: return new ListComponent(ID, u); :} | ID COL s_type_use.u STAR {: return new ListComponent(ID, u); :}
| s_type_use.u STAR {: return new ListComponent(u.getID(), u); :} | s_type_use.u STAR {: return new ListComponent(u.getID(), u); :}
// Opt // Opt
| LBRACKET ID COL s_type_use.u RBRACKET {: return new OptComponent(ID, 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); :} | LBRACKET s_type_use.u RBRACKET {: return new OptComponent(u.getID(), u); :}
// NTA // NTA
| SLASH ID COL s_type_use.u SLASH {: return new NTAComponent(ID, 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); :} | SLASH s_type_use.u SLASH {: return new NTAComponent(u.getID(), u); :}
// NTA Token (same as NTA) // NTA Token (same as NTA)
| SLASH LT ID COL s_type_use.u GT SLASH {: return new NTAComponent(ID, 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); :} | SLASH LT s_type_use.u GT SLASH {: return new NTAComponent(u.getID(), u); :}
// Token // Token
| LT ID COL type_use.u GT {: return new TokenComponent(ID, u); :} | LT ID COL type_use.u GT {: return new TokenComponent(ID, u); :}
| LT ID GT {: return new TokenComponent(ID, new SimpleTypeUse("String")); :} | LT ID GT {: return new TokenComponent(ID, new SimpleTypeUse("String")); :}
; ;
Relation relation = Relation relation =
RELATION relation_comp.l direction relation_comp.r SCOL 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 = RelationComponent relation_comp =
// One // One
s_type_use.u DOT ID {: return new OneRelationComponent(ID, u); :} s_type_use.u DOT ID {: return new OneRelationComponent(ID, u); :}
| s_type_use.u {: return new OneRelationComponent("", u); :} | s_type_use.u {: return new OneRelationComponent("", u); :}
// Optional // Optional
| s_type_use.u DOT ID QUESTION_MARK {: return new OptionalRelationComponent(ID, u); :} | 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 QUESTION_MARK {: return new OptionalRelationComponent("", u); :}
// Many // Many
| s_type_use.u DOT ID STAR {: return new ManyRelationComponent(ID, u); :} | 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 STAR {: return new ManyRelationComponent("", u); :}
; ;
Direction direction = Direction direction =
......
...@@ -14,7 +14,7 @@ import java.util.List; ...@@ -14,7 +14,7 @@ import java.util.List;
public class Compiler { public class Compiler {
private static final String VERSION = "0.2.1"; private static final String VERSION = "0.2.2";
private ArrayList<Option<?>> options; private ArrayList<Option<?>> options;
private FlagOption optionWriteToFile; private FlagOption optionWriteToFile;
...@@ -177,9 +177,11 @@ public class Compiler { ...@@ -177,9 +177,11 @@ public class Compiler {
try { try {
Program newProgram = (Program) parser.parse(scanner); Program newProgram = (Program) parser.parse(scanner);
for (TypeDecl typeDecl : newProgram.getTypeDeclList()) { for (TypeDecl typeDecl : newProgram.getTypeDeclList()) {
typeDecl.setFileName(file);
program.addTypeDecl(typeDecl); program.addTypeDecl(typeDecl);
} }
for (Relation relation : newProgram.getRelationList()) { for (Relation relation : newProgram.getRelationList()) {
relation.setFileName(file);
program.addRelation(relation); program.addRelation(relation);
} }
} catch (IOException e) { } catch (IOException e) {
......
Errors: Errors:
Line 5, column 5: Role name missing for type 'A' $FILENAME Line 5, column 5: Role name missing for type 'A'
Line 6, column 15: Role name missing for type 'B' $FILENAME 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 $FILENAME 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 8, column 13: The target of a directed relation may only have multiplicity 1
Errors: Errors:
Line 2, column 12: Component 'X' is already declared for type 'B1' $FILENAME 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 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; ...@@ -9,6 +9,9 @@ import org.junit.jupiter.api.Test;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.Charset; 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.exec;
import static org.jastadd.relast.tests.TestHelpers.readFile; import static org.jastadd.relast.tests.TestHelpers.readFile;
...@@ -17,39 +20,33 @@ import static org.jastadd.relast.tests.TestHelpers.readFile; ...@@ -17,39 +20,33 @@ import static org.jastadd.relast.tests.TestHelpers.readFile;
class Errors { class Errors {
private static final Logger logger = LogManager.getLogger(Errors.class); private static final Logger logger = LogManager.getLogger(Errors.class);
private static final String FILENAME_PATTERN = "$FILENAME";
@Test @Test
void test1() throws IOException { void test1() throws IOException {
test("Errors");
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 @Test
void test2() throws IOException { void test2() throws IOException {
test("Inheritance");
}
String inFile = "./src/test/jastadd/errors/Inheritance.relast"; @Test
String outFile = "./src/test/jastadd/errors/Inheritance.out"; void test3() throws IOException {
String expectedFile = "./src/test/jastadd/errors/Inheritance.expected"; 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 { try {
System.out.println(System.getProperty("user.dir")); 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"); Assertions.assertEquals(1, returnValue, "Relast did not return with value 1");
} catch (IOException | InterruptedException e) { } catch (IOException | InterruptedException e) {
e.printStackTrace(); e.printStackTrace();
...@@ -57,10 +54,16 @@ class Errors { ...@@ -57,10 +54,16 @@ class Errors {
String out = readFile(outFile, Charset.defaultCharset()); String out = readFile(outFile, Charset.defaultCharset());
String expected = readFile(expectedFile, 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 for " + name + " returned \n{}", out);
logger.info("'relast Inheritance.relast' 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