import java.util.Set; import java.util.TreeSet; import java.util.LinkedList; aspect Errors { coll Set Program.errors() [new TreeSet()] root Program; TypeUse contributes error("Type '" + getID() + "' not found") when decl() == null && !isToken() to Program.errors(); TypeDecl contributes error("Type '" + getID() + "' is already declared") when isAlreadyDeclared() to Program.errors(); Component contributes error("Component '" + name() + "' is already declared for type '" + toTypeDecl() + "'") when isAlreadyDeclared() to Program.errors(); Component contributes error("Component '" + name() + "' is an invalid redefition for type '" + toTypeDecl() + "'") when isInvalidRedefinition() to Program.errors(); RelationComponent contributes error("Role name missing for type '" + toTypeDecl() + "'") when !isTargetOfDirectedRelation() && name().isEmpty() to Program.errors(); RelationComponent contributes error("The target of a directed relation cannot have a role name") when isTargetOfDirectedRelation() && !getID().isEmpty() to Program.errors(); RelationComponent contributes error("The target of a directed relation may only have multiplicity 1") when isTargetOfDirectedRelation() && !multiplicityOne() to Program.errors(); } aspect HelpAttributes { inh Program ASTNode.program(); eq Program.getChild().program() = this; inh boolean TypeUse.isToken(); eq Program.getChild().isToken() = false; eq TokenComponent.getTypeUse().isToken() = true; syn boolean RelationComponent.multiplicityOne() = false; eq OneRelationComponent.multiplicityOne() = true; syn boolean RelationComponent.multiplicityOpt() = false; 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 { 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; } public ASTNode getNode() { return node; } public int getLine() { return line; } public int getCol() { return col; } public String getMessage() { return message; } public String toString() { return filename + " Line " + line + ", column " + col + ": " + message; } @Override public int compareTo(ErrorMessage err) { int n = filename.compareTo(err.filename); if (n != 0) { return n; } n = line - err.line; if (n != 0) { return n; } n = col-err.col; if (n != 0) { return n; } return message.compareTo(err.message); } } protected ErrorMessage ASTNode.error(String message) { return new ErrorMessage(this, message); } }