diff --git a/src/main/java/edu/kit/typicalc/model/parser/LambdaLexer.java b/src/main/java/edu/kit/typicalc/model/parser/LambdaLexer.java index 27f128f..52aecc5 100644 --- a/src/main/java/edu/kit/typicalc/model/parser/LambdaLexer.java +++ b/src/main/java/edu/kit/typicalc/model/parser/LambdaLexer.java @@ -90,7 +90,7 @@ public class LambdaLexer { return new Result<>(t); } else { return new Result<>(null, ParseError.UNEXPECTED_CHARACTER - .withCharacter(term.charAt(pos + 1), pos + 1, term)); + .withCharacter(term.charAt(pos + 1), pos + 1, term, ParseError.ErrorType.TERM_ERROR)); } } else { return new Result<>(null, ParseError.TOO_FEW_TOKENS); // actually too few *characters* .. @@ -148,7 +148,7 @@ public class LambdaLexer { && (int) term.charAt(pos) < 128); if (pos < term.length() && (int) term.charAt(pos) >= 128) { return new Result<>(null, ParseError.UNEXPECTED_CHARACTER - .withCharacter(term.charAt(pos), pos, term)); + .withCharacter(term.charAt(pos), pos, term, ParseError.ErrorType.TERM_ERROR)); } String s = sb.toString(); TokenType type; @@ -180,7 +180,8 @@ public class LambdaLexer { } while (pos < term.length() && Character.isDigit(term.charAt(pos))); return new Result<>(new Token(TokenType.NUMBER, sb.toString(), term, startPos)); } else { - return new Result<>(null, ParseError.UNEXPECTED_CHARACTER.withCharacter(c, pos, term)); + return new Result<>(null, ParseError.UNEXPECTED_CHARACTER.withCharacter(c, pos, term, + ParseError.ErrorType.TERM_ERROR)); } } diff --git a/src/main/java/edu/kit/typicalc/model/parser/LambdaParser.java b/src/main/java/edu/kit/typicalc/model/parser/LambdaParser.java index 5addd87..f1c9c5d 100644 --- a/src/main/java/edu/kit/typicalc/model/parser/LambdaParser.java +++ b/src/main/java/edu/kit/typicalc/model/parser/LambdaParser.java @@ -69,7 +69,8 @@ public class LambdaParser { TokenType current = token.getType(); Optional error = nextToken(); if (current != type) { - return Optional.of(ParseError.UNEXPECTED_TOKEN.withToken(lastToken).expectedType(type)); + return Optional.of(ParseError.UNEXPECTED_TOKEN.withToken(lastToken, + ParseError.ErrorType.TERM_ERROR).expectedType(type)); } return error; } @@ -91,7 +92,7 @@ public class LambdaParser { } return new Result<>(null, (last.getType() == TokenType.EOF ? ParseError.TOO_FEW_TOKENS : ParseError.UNEXPECTED_TOKEN) - .withToken(last) + .withToken(last, ParseError.ErrorType.TERM_ERROR) .expectedTypes(ATOM_START_TOKENS)); } @@ -207,7 +208,8 @@ public class LambdaParser { try { n = Integer.parseInt(number); } catch (NumberFormatException e) { - return new Result<>(null, ParseError.UNEXPECTED_CHARACTER.withToken(token)); + return new Result<>(null, ParseError.UNEXPECTED_CHARACTER.withToken( + token, ParseError.ErrorType.TERM_ERROR)); } error = nextToken(); if (error.isEmpty()) { diff --git a/src/main/java/edu/kit/typicalc/model/parser/ParseError.java b/src/main/java/edu/kit/typicalc/model/parser/ParseError.java index 59a5560..721fd30 100644 --- a/src/main/java/edu/kit/typicalc/model/parser/ParseError.java +++ b/src/main/java/edu/kit/typicalc/model/parser/ParseError.java @@ -30,6 +30,23 @@ public enum ParseError { */ UNEXPECTED_CHARACTER; + public enum ErrorType { + /** + * This error was created when parsing the input term + */ + TERM_ERROR, + + /** + * This error was created when parsing the type assumptions + */ + TYPE_ASSUMPTION_ERROR, + + /** + * initial error type + */ + INITIAL_ERROR + } + private Optional cause = Optional.empty(); private Optional> needed = Optional.empty(); private Optional expected = Optional.empty(); @@ -37,6 +54,7 @@ public enum ParseError { private char wrongChar = '\0'; private char correctChar = '\0'; private int position = -1; + private ErrorType errorType = ErrorType.INITIAL_ERROR; /** * Attach a token to this error. @@ -44,10 +62,11 @@ public enum ParseError { * @param cause the token that caused the error * @return this object */ - public ParseError withToken(Token cause) { + public ParseError withToken(Token cause, ErrorType errorType) { this.cause = Optional.of(cause); this.term = cause.getSourceText(); this.position = cause.getPos(); + this.errorType = errorType; return this; } @@ -108,10 +127,11 @@ public enum ParseError { * @param term the term that is parsed * @return this object */ - public ParseError withCharacter(char cause, int position, String term) { + public ParseError withCharacter(char cause, int position, String term, ErrorType errorType) { this.wrongChar = cause; this.position = position; this.term = term; + this.errorType = errorType; return this; } @@ -157,6 +177,17 @@ public enum ParseError { return term; } + /** + * @return the error type + */ + public ErrorType getErrorType() { + return errorType; + } + + protected void setErrorType(ErrorType errorType) { + this.errorType = errorType; + } + ParseError() { } diff --git a/src/main/java/edu/kit/typicalc/model/parser/TypeAssumptionParser.java b/src/main/java/edu/kit/typicalc/model/parser/TypeAssumptionParser.java index bc4a477..b9ff37d 100644 --- a/src/main/java/edu/kit/typicalc/model/parser/TypeAssumptionParser.java +++ b/src/main/java/edu/kit/typicalc/model/parser/TypeAssumptionParser.java @@ -143,7 +143,8 @@ public class TypeAssumptionParser { case EOF: return new ParserResult<>(alreadyParsed); default: - return new ParserResult<>(ParseError.UNEXPECTED_TOKEN.withToken(t)); + return new ParserResult<>(ParseError.UNEXPECTED_TOKEN + .withToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); } } } @@ -162,7 +163,8 @@ public class TypeAssumptionParser { case COLON: return new ParserResult<>(new ExpectingTypeDef(alreadyParsed, var)); default: - return new ParserResult<>(ParseError.UNEXPECTED_TOKEN.withToken(t)); + return new ParserResult<>(ParseError.UNEXPECTED_TOKEN + .withToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); } } } @@ -191,7 +193,8 @@ public class TypeAssumptionParser { if (typeVariables.isEmpty()) { return new ParserResult<>(new ExpectingTypeVariables(alreadyParsed, var)); } else { - return new ParserResult<>(ParseError.UNEXPECTED_TOKEN.withToken(t)); + return new ParserResult<>(ParseError.UNEXPECTED_TOKEN + .withToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); } default: if (state.isPresent()) { @@ -235,7 +238,8 @@ public class TypeAssumptionParser { case COMMA: return new ParserResult<>(new InitialState(alreadyParsed)); default: - return new ParserResult<>(ParseError.UNEXPECTED_TOKEN.withToken(t)); + return new ParserResult<>(ParseError.UNEXPECTED_TOKEN + .withToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); } } } @@ -261,7 +265,8 @@ public class TypeAssumptionParser { return handleInnerParenthesis(t); } if (parsedType.isPresent()) { - return new ParserResult<>(ParseError.UNEXPECTED_TOKEN.withToken(t)); + return new ParserResult<>(ParseError.UNEXPECTED_TOKEN + .withToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); } Type type = parseLiteral(t.getText()); // try parsing function type (see below) @@ -275,7 +280,8 @@ public class TypeAssumptionParser { return handleInnerParenthesis(t); } if (parsedType.isEmpty()) { - return new ParserResult<>(ParseError.UNEXPECTED_TOKEN.withToken(t)); + return new ParserResult<>(ParseError.UNEXPECTED_TOKEN + .withToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); } // parse function type state = Optional.of(new ParseTypeStateExpectArrow().handle(t).getState()); @@ -314,7 +320,8 @@ public class TypeAssumptionParser { if (parsedType.isPresent()) { return new ParserResult<>(this); // parenthesized part may be start of function } - return new ParserResult<>(ParseError.UNEXPECTED_TOKEN.withToken(t)); + return new ParserResult<>(ParseError.UNEXPECTED_TOKEN + .withToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); case COMMA: case EOF: if (state.isPresent()) { @@ -326,12 +333,14 @@ public class TypeAssumptionParser { if (parsedType.isPresent() && openParens == parenthesisInitial) { return new ParserResult<>(parsedType.get()).attachToken(t); } - return new ParserResult<>(ParseError.UNEXPECTED_TOKEN.withToken(t)); + return new ParserResult<>(ParseError.UNEXPECTED_TOKEN + .withToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); default: if (state.isPresent()) { return handleInner(t); } - return new ParserResult<>(ParseError.UNEXPECTED_TOKEN.withToken(t)); + return new ParserResult<>(ParseError.UNEXPECTED_TOKEN + .withToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); } } @@ -400,7 +409,8 @@ public class TypeAssumptionParser { return new ParserResult<>(this); } } else { - return new ParserResult<>(ParseError.UNEXPECTED_TOKEN.withToken(t)); + return new ParserResult<>(ParseError.UNEXPECTED_TOKEN + .withToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); } } } @@ -422,13 +432,13 @@ public class TypeAssumptionParser { case VARIABLE: if (expectCommaOrDot) { return new ParserResult<>(ParseError.UNEXPECTED_TOKEN - .withToken(t) + .withToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR) .expectedTypes(List.of(TokenType.COMMA, Token.TokenType.DOT))); } String input = t.getText(); if (!TYPE_VARIABLE_PATTERN.matcher(input).matches()) { - return new ParserResult<>(ParseError.UNEXPECTED_TOKEN.withToken(t)); - // TODO: somehow convey the expected format + return new ParserResult<>(ParseError.UNEXPECTED_TOKEN + .withToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); } int i = Integer.parseInt(input.substring(1)); variables.add(new TypeVariable(TypeVariableKind.USER_INPUT, i)); @@ -440,7 +450,7 @@ public class TypeAssumptionParser { return new ParserResult<>(this); } else { return new ParserResult<>(ParseError.UNEXPECTED_TOKEN - .withToken(t) + .withToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR) .expectedType(TokenType.VARIABLE)); } case DOT: @@ -450,15 +460,17 @@ public class TypeAssumptionParser { return new ParserResult<>(new ExpectingTypeDef(alreadyParsed, variables, var)); } else { return new ParserResult<>(ParseError.UNEXPECTED_TOKEN - .withToken(t) + .withToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR) .expectedType(TokenType.VARIABLE)); } default: if (expectCommaOrDot) { - return new ParserResult<>(ParseError.UNEXPECTED_TOKEN.withToken(t) + return new ParserResult<>(ParseError.UNEXPECTED_TOKEN + .withToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR) .expectedTypes(List.of(TokenType.COMMA, TokenType.DOT))); } - return new ParserResult<>(ParseError.UNEXPECTED_TOKEN.withToken(t)); + return new ParserResult<>(ParseError.UNEXPECTED_TOKEN + .withToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); } } } diff --git a/src/main/java/edu/kit/typicalc/view/content/errorcontent/ErrorView.java b/src/main/java/edu/kit/typicalc/view/content/errorcontent/ErrorView.java index cfae822..42801b5 100644 --- a/src/main/java/edu/kit/typicalc/view/content/errorcontent/ErrorView.java +++ b/src/main/java/edu/kit/typicalc/view/content/errorcontent/ErrorView.java @@ -54,27 +54,36 @@ public class ErrorView extends VerticalLayout implements LocaleChangeObserver { Paragraph summary = new Paragraph(getTranslation("root." + error.toString())); summary.setId(ERROR_SUMMARY_ID); String term = error.getTerm(); - + String descriptionForError; + ParseError.ErrorType errorType = error.getErrorType(); + if (errorType == ParseError.ErrorType.TERM_ERROR) { + descriptionForError = "error.termForError"; + } else if (errorType == ParseError.ErrorType.TYPE_ASSUMPTION_ERROR) { + descriptionForError = "error.typeAssumptionForError"; + } else { + //should never happen + descriptionForError = "error"; + } switch (error) { case TOO_FEW_TOKENS: - additionalInformation.add(new Span(getTranslation("root.tooFewTokensHelp"))); + additionalInformation.add(new Span(getTranslation("error.tooFewTokensHelp"))); break; case UNEXPECTED_TOKEN: Optional cause = error.getCause(); if (cause.isPresent()) { - additionalInformation.add(new Span(new Pre(getTranslation("root.termForError") + term - + "\n" + " ".repeat(Math.max(getTranslation("root.termForError").length(), - cause.get().getPos() + getTranslation("root.termForError").length())) - + "^ " + getTranslation("root.wrongCharacter") + cause.get().getText()))); + additionalInformation.add(new Span(new Pre(getTranslation(descriptionForError) + term + + "\n" + " ".repeat(Math.max(getTranslation(descriptionForError).length(), + cause.get().getPos() + getTranslation(descriptionForError).length())) + + "^ " + getTranslation("error.wrongCharacter") + cause.get().getText()))); } break; case UNEXPECTED_CHARACTER: char c = error.getWrongCharacter(); if (c != '\0') { - additionalInformation.add(new Span(new Pre(getTranslation("root.termForError") + term - + "\n" + " ".repeat(Math.max(getTranslation("root.termForError").length(), - error.getPosition() + getTranslation("root.termForError").length())) - + "^ " + getTranslation("root.wrongCharacter") + c))); + additionalInformation.add(new Span(new Pre(getTranslation(descriptionForError) + term + + "\n" + " ".repeat(Math.max(getTranslation(descriptionForError).length(), + error.getPosition() + getTranslation(descriptionForError).length())) + + "^ " + getTranslation("error.wrongCharacter") + c))); } else { return summary; } diff --git a/src/main/resources/language/translation_de.properties b/src/main/resources/language/translation_de.properties index c173010..ba5083e 100644 --- a/src/main/resources/language/translation_de.properties +++ b/src/main/resources/language/translation_de.properties @@ -101,12 +101,13 @@ help.typicalcInfo=\ Johanna Stuber
root.TOO_FEW_TOKENS=Falsche Eingabe! Die Eingabe endet abrupt. -root.tooFewTokensHelp=Überprüfe, ob alle Let-, Abs- und App-Terme über die nötigen Argumente verfügen. +error.tooFewTokensHelp=Überprüfe, ob alle Let-, Abs- und App-Terme über die nötigen Argumente verfügen. root.UNEXPECTED_TOKEN=Die Eingabe entspricht nicht der im Info-Dialog spezifizierten Syntax! root.UNEXPECTED_CHARACTER=Die Eingabe enthält ein Zeichen, welches an dieser Stelle nicht erlaubt ist! error.heading=Syntaktisch falsche Eingabe! -root.termForError=Term:\u0020 -root.wrongCharacter=Falsches Zeichen:\u0020 +error.termForError=Term:\u0020 +error.typeAssumptionForError=Typannahme:\u0020 +error.wrongCharacter=Falsches Zeichen:\u0020 error.expectedToken=Erwartet: {0} error.hint=Die Grammatiken, die die korrekte Syntax eines Terms und der Typannahmen beschreiben, \ sind auch über das Info-Symbol zu erreichen. diff --git a/src/main/resources/language/translation_en.properties b/src/main/resources/language/translation_en.properties index 76cab63..af04a39 100644 --- a/src/main/resources/language/translation_en.properties +++ b/src/main/resources/language/translation_en.properties @@ -94,12 +94,13 @@ help.typicalcInfo=\ Johanna Stuber root.TOO_FEW_TOKENS=Wrong input! The term ends abruptly. -root.tooFewTokensHelp=Check if all let, abstraction and application terms consist of the required arguments. +error.tooFewTokensHelp=Check if all let, abstraction and application terms consist of the required arguments. root.UNEXPECTED_TOKEN=The input does not match the syntax specified in the info dialog. root.UNEXPECTED_CHARACTER=The input contains a character which is not allowed at this position. error.heading=Input is syntactically wrong! -root.wrongCharacter=Wrong character:\u0020 -root.termForError=Term:\u0020 +error.wrongCharacter=Wrong character:\u0020 +error.termForError=Term:\u0020 +error.typeAssumptionForError=Type Assumption:\u0020 error.expectedToken=Expected: {0} error.hint=The grammars describing the correct syntax of a term or a type assumption can also be reached \ via the info icon. diff --git a/src/test/java/edu/kit/typicalc/model/parser/TypeAssumptionParserTest.java b/src/test/java/edu/kit/typicalc/model/parser/TypeAssumptionParserTest.java index 71f7c12..ac37554 100644 --- a/src/test/java/edu/kit/typicalc/model/parser/TypeAssumptionParserTest.java +++ b/src/test/java/edu/kit/typicalc/model/parser/TypeAssumptionParserTest.java @@ -232,17 +232,23 @@ class TypeAssumptionParserTest { void errors() { Map tests = new HashMap<>(); tests.put("", - ParseError.UNEXPECTED_TOKEN.withToken(new Token(Token.TokenType.EOF, "", "", 0))); + ParseError.UNEXPECTED_TOKEN.withToken(new Token(Token.TokenType.EOF, "", "", 0), + ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); tests.put("ö", ParseError.UNEXPECTED_CHARACTER); tests.put("(x", - ParseError.UNEXPECTED_TOKEN.withToken(new Token(Token.TokenType.EOF, "", "(x", 2))); + ParseError.UNEXPECTED_TOKEN.withToken(new Token(Token.TokenType.EOF, "", "(x", 2), + ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); tests.put("-> x", - ParseError.UNEXPECTED_TOKEN.withToken(new Token(Token.TokenType.ARROW, "->", "-> x", 0))); + ParseError.UNEXPECTED_TOKEN.withToken(new Token(Token.TokenType.ARROW, "->", "-> x", 0), + ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); tests.put("x 11", - ParseError.UNEXPECTED_TOKEN.withToken(new Token(Token.TokenType.NUMBER, "11", "x 11", 2))); - tests.put("x )", ParseError.UNEXPECTED_TOKEN.withToken(new Token(Token.TokenType.RIGHT_PARENTHESIS, ")", "x )", 2))); + ParseError.UNEXPECTED_TOKEN.withToken(new Token(Token.TokenType.NUMBER, "11", "x 11", 2), + ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); + tests.put("x )", ParseError.UNEXPECTED_TOKEN.withToken(new Token(Token.TokenType.RIGHT_PARENTHESIS, ")", "x )", 2), + ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); tests.put("x -> (x) )", ParseError.UNEXPECTED_TOKEN - .withToken(new Token(Token.TokenType.RIGHT_PARENTHESIS, ")", "x -> (x) )", 9))); + .withToken(new Token(Token.TokenType.RIGHT_PARENTHESIS, ")", "x -> (x) )", 9), + ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); for (Map.Entry entry : tests.entrySet()) { TypeAssumptionParser parser = new TypeAssumptionParser(); Result, ParseError> type = parser.parse("type1:" + entry.getKey());