Files
exercise02/MicroJava Compiler/src/ssw/mj/Errors.java

141 lines
6.4 KiB
Java

package ssw.mj;
import java.io.Serial;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
public class Errors {
public static class PanicMode extends Error {
@Serial
private static final long serialVersionUID = 1L;
// Nothing to implement here.
}
public enum Message {
// ----- error messages first used in ScannerTest
EMPTY_CHARCONST("empty character constant"),
UNDEFINED_ESCAPE("undefined escape character sequence ''\\{0}''"),
MISSING_QUOTE("missing '' at end of character constant"),
INVALID_CHAR("invalid character {0}"),
BIG_NUM("{0} too big for integer constant"),
EOF_IN_COMMENT("unexpected end of file in comment"),
EOF_IN_CHAR("unexpected end of file in char"),
ILLEGAL_LINE_END("illegal line end in character constant"),
// ----- error messages first used in ParserTest
INVALID_ADD_OP("unexpected token. + or - expected"), // cannot occur in current grammar version, but still must be placed correctly (in default case of respective switch)
INVALID_ASSIGN_OP("unexpected token. =, +=, -=, *=, /=, %= expected"), // cannot occur in current grammar version, but still must be placed correctly (in default case of respective switch)
INVALID_MUL_OP("unexpected token. *, /, % expected"), // cannot occur in current grammar version, but still must be placed correctly (in default case of respective switch)
INVALID_METHOD_DECL("invalid start of method decl: type name or void expected"), // cannot occur in current grammar version, but still must be placed correctly (in default case of respective switch)
INVALID_STATEMENT("unexpected token. identifier, if, while, break, return, read, print, '{' or ; expected"), // cannot occur in current grammar version, but still must be placed correctly (in default case of respective switch)
INVALID_DESIGNATOR_STATEMENT("unexpected token. assignment token (=, +=, -=, *=, /=, %=), method call (\"(\"), increment (++) or decrement (--) expected"),
INVALID_CONST_TYPE("number or character constant expected"),
INVALID_FACTOR("unexpected token. identifier, number, character constant, new or \"(\" expected"),
INVALID_REL_OP("unexpected token. ==, !=, >, >=, <, <= expected"),
TOKEN_EXPECTED("{0} expected"),
// ----- error messages first used in RecoverTest
DECLARATION_RECOVERY("start or follow of declaration expected"),
METHOD_DECL_RECOVERY("start or follow of method declaration expected"),
STATEMENT_RECOVERY("start or follow of statement expected"),
// ----- error messages first used in SymbolTableTest
INCOMPATIBLE_TYPES("incompatible types"), // mainly used in SimpleCodeGenerationTest, but also in SymbolTableTest
DUPLICATE_NAME_IN_SCOPE("{0} already declared in current scope"),
MAIN_WITH_PARAMS("main method must not have any parameters"),
MAIN_NOT_VOID("main method must return void"),
FIELD_NOT_FOUND("{0} is not a field"),
TYPE_EXPECTED("type expected"),
NAME_NOT_FOUND("{0} not found"),
TOO_MANY_FIELDS("too many fields"),
TOO_MANY_GLOBALS("too many global variables"),
TOO_MANY_LOCALS("too many local variables"),
CLASS_TYPE_EXPECTED("can only instantiate new object for a class"),
// ----- error messages first used in SimpleCodeGenerationTest
ARRAY_INDEX_EXPECTS_INT("array index must be an integer"),
ARRAY_SIZE_EXPECTS_INT("array size must be an integer"),
CANNOT_STORE_TO_READONLY("cannot store to readonly operand of kind {0}"),
VOID_CALL_IN_EXPRESSION("cannot use void method as part of expression"),
MAIN_NOT_FOUND("mainPC is -1, main not found (did you forget to set code.mainPC? ;))"),
INDEXED_ACCESS_TO_NON_ARRAY("indexed object is not an array"),
FIELD_ACCESS_TO_NON_CLASS("accessed object is not of kind class"),
ILLEGAL_OPERAND_KIND("cannot create operand symbol table object of type {0}"),
CANNOT_LOAD_OPERAND("already loaded (stack) or loadable operand (const, local, static, field, array element) expected"),
ILLEGAL_PRINT_ARGUMENT("can only print int or char values"),
ILLEGAL_READ_ARGUMENT("can only read int or char values"),
INC_DEC_EXPECTS_INT("increment and decrement only allowed for int"),
UNARY_MINUS_EXPECTS_INT("unary minus only allowed for int"),
// ----- error messages first used in CodeGenerationTest
ILLEGAL_REFERENCE_COMPARISON("only equality and unequality checks are allowed for reference types"),
ILLEGAL_METHOD_RETURN_TYPE("methods may only return int or char"),
WRONG_ARGUMENT_COUNT("number of arguments and formal parameters does not match"),
BREAK_OUTSIDE_LOOP("break is not within a loop"),
CALL_TO_NON_METHOD("called object is not a method"),
ARGUMENT_TYPE_MISMATCH("argument type does not match formal parameter type"),
MISSING_RETURN_VALUE("return expression required in non-void method"),
UNEXPECTED_RETURN_VALUE("no return expression allowed in void method"),
RETURN_TYPE_MISMATCH("return type must match method type");
private final String msg;
Message(String msg) {
this.msg = msg;
}
public String format(Object... params) {
int expectedParams = 0;
while (msg.contains("{" + expectedParams + "}")) {
expectedParams++;
}
if (params.length != expectedParams) {
throw new Error("incorrect number of error message parameters. Expected %d but got %d".formatted(expectedParams, params.length));
}
return MessageFormat.format(msg, params);
}
}
/**
* List of error messages.
*/
private final List<String> errors;
/**
* Initialization (must be called before compilation).
*/
public Errors() {
errors = new ArrayList<>();
}
/**
* Add a new error message to the list of errors.
*/
public void error(int line, int col, Message msg, Object... msgParams) {
errors.add("-- line " + line + " col " + col + ": " + msg.format(msgParams));
}
/**
* Returns the number of errors.
*/
public int numErrors() {
return errors.size();
}
/**
* String representation for JUnit test cases.
*/
public String dump() {
StringBuilder sb = new StringBuilder();
for (String error : errors) {
sb.append(error).append("\n");
}
return sb.toString();
}
public List<String> getErrors() {
return errors;
}
}