From 0285305f139aecb73b14a13ada43eeec09454dfe Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Mon, 19 Jul 2021 10:56:46 +0200 Subject: [PATCH] Refactor ParseError into object instead of enum See #12 --- .../edu/kit/typicalc/model/ModelImpl.java | 1 + .../typicalc/model/parser/LambdaLexer.java | 18 +-- .../typicalc/model/parser/LambdaParser.java | 12 +- .../kit/typicalc/model/parser/ParseError.java | 104 +++++++++++++++--- .../model/parser/TypeAssumptionParser.java | 92 +++++++++------- .../view/content/errorcontent/ErrorView.java | 3 +- .../model/parser/LambdaParserTest.java | 48 ++++---- .../parser/TypeAssumptionParserTest.java | 42 ++++--- 8 files changed, 211 insertions(+), 109 deletions(-) diff --git a/src/main/java/edu/kit/typicalc/model/ModelImpl.java b/src/main/java/edu/kit/typicalc/model/ModelImpl.java index acf1e21..76080b8 100644 --- a/src/main/java/edu/kit/typicalc/model/ModelImpl.java +++ b/src/main/java/edu/kit/typicalc/model/ModelImpl.java @@ -28,6 +28,7 @@ public class ModelImpl implements Model { @Override public Result getTypeInferer(String lambdaTerm, String typeAssumptions) { + System.out.println(lambdaTerm); // Parse Lambda Term LambdaParser parser = new LambdaParser(lambdaTerm); Result result = parser.parse(); 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 5290e5d..2b45a47 100644 --- a/src/main/java/edu/kit/typicalc/model/parser/LambdaLexer.java +++ b/src/main/java/edu/kit/typicalc/model/parser/LambdaLexer.java @@ -16,6 +16,7 @@ public class LambdaLexer { * the given term as a String */ private final String term; + private final ParseError.ErrorType errorType; /** * current position in the term */ @@ -27,8 +28,9 @@ public class LambdaLexer { * * @param term the term to lex */ - public LambdaLexer(String term) { + public LambdaLexer(String term, ParseError.ErrorType errorType) { this.term = term; + this.errorType = errorType; Deque tokens = new ArrayDeque<>(); while (true) { Result token = parseNextToken(); @@ -89,13 +91,12 @@ public class LambdaLexer { advance(); return new Result<>(t); } else { - return new Result<>(null, ParseError.UNEXPECTED_CHARACTER - .withCharacter(term.charAt(pos + 1), pos + 1, term, ParseError.ErrorType.TERM_ERROR)); + return new Result<>(null, ParseError.unexpectedCharacter2( + term.charAt(pos + 1), pos + 1, term, errorType)); } } else { return new Result<>(null, - ParseError.UNEXPECTED_CHARACTER - .withCharacter(' ', term.length(), term, ParseError.ErrorType.TERM_ERROR)); + ParseError.unexpectedCharacter2(' ', term.length(), term, errorType)); } // bunch of single-character tokens case '.': @@ -149,8 +150,7 @@ public class LambdaLexer { } while (pos < term.length() && Character.isLetterOrDigit(term.charAt(pos)) && (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, ParseError.ErrorType.TERM_ERROR)); + return new Result<>(null, ParseError.unexpectedCharacter2(term.charAt(pos), pos, term, errorType)); } String s = sb.toString(); TokenType type; @@ -182,8 +182,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, - ParseError.ErrorType.TERM_ERROR)); + return new Result<>(null, ParseError.unexpectedCharacter2(c, pos, term, + errorType)); } } 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 aca2f8b..5bd1533 100644 --- a/src/main/java/edu/kit/typicalc/model/parser/LambdaParser.java +++ b/src/main/java/edu/kit/typicalc/model/parser/LambdaParser.java @@ -42,7 +42,7 @@ public class LambdaParser { * @param term String to parse */ public LambdaParser(String term) { - this.lexer = new LambdaLexer(term); + this.lexer = new LambdaLexer(term, ParseError.ErrorType.TERM_ERROR); } /** @@ -69,7 +69,7 @@ public class LambdaParser { TokenType current = token.getType(); Optional error = nextToken(); if (current != type) { - return Optional.of(ParseError.UNEXPECTED_TOKEN.withToken(lastToken, + return Optional.of(ParseError.unexpectedToken(lastToken, ParseError.ErrorType.TERM_ERROR).expectedType(type)); } return error; @@ -91,8 +91,7 @@ public class LambdaParser { return t; } return new Result<>(null, - ParseError.UNEXPECTED_TOKEN - .withToken(last, ParseError.ErrorType.TERM_ERROR) + ParseError.unexpectedToken(last, ParseError.ErrorType.TERM_ERROR) .expectedTypes(ATOM_START_TOKENS)); } @@ -109,8 +108,7 @@ public class LambdaParser { } } if (token.getType() == TokenType.EOF) { - return new Result<>(null, ParseError.UNEXPECTED_TOKEN - .withToken(token, ParseError.ErrorType.TERM_ERROR) + return new Result<>(null, ParseError.unexpectedToken(token, ParseError.ErrorType.TERM_ERROR) .expectedInput(ExpectedInput.TERM)); } return parseApplication(); @@ -210,7 +208,7 @@ public class LambdaParser { try { n = Integer.parseInt(number); } catch (NumberFormatException e) { - return new Result<>(null, ParseError.UNEXPECTED_CHARACTER.withToken( + return new Result<>(null, ParseError.unexpectedCharacter( token, ParseError.ErrorType.TERM_ERROR)); } error = nextToken(); 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 a180efa..9cd9d0b 100644 --- a/src/main/java/edu/kit/typicalc/model/parser/ParseError.java +++ b/src/main/java/edu/kit/typicalc/model/parser/ParseError.java @@ -1,8 +1,6 @@ package edu.kit.typicalc.model.parser; -import java.util.Collection; -import java.util.List; -import java.util.Optional; +import java.util.*; /** * Errors that can occur when parsing a lambda term or type assumption. @@ -10,17 +8,44 @@ import java.util.Optional; * @see LambdaLexer * @see LambdaParser */ -public enum ParseError { +public final class ParseError { - /** - * the lambda term didn't meet the specified syntax - */ - UNEXPECTED_TOKEN, + private ParseError(ErrorCause unexpectedToken) { + this.causeEnum = unexpectedToken; + } - /** - * the string contained a character not allowed in that context - */ - UNEXPECTED_CHARACTER; + public enum ErrorCause { + /** + * the lambda term didn't meet the specified syntax + */ + UNEXPECTED_TOKEN, + + /** + * the string contained a character not allowed in that context + */ + UNEXPECTED_CHARACTER + } + + private final ErrorCause causeEnum; + + public ErrorCause getCauseEnum() { + return causeEnum; + } + + public static ParseError unexpectedToken(Token cause, ErrorType source) { + var self = new ParseError(ErrorCause.UNEXPECTED_TOKEN); + return self.withToken(cause, source); + } + + public static ParseError unexpectedCharacter(Token cause, ErrorType source) { + var self = new ParseError(ErrorCause.UNEXPECTED_CHARACTER); + return self.withToken(cause, source); + } + + public static ParseError unexpectedCharacter2(char cause, int position, String term, ErrorType errorType) { + var self = new ParseError(ErrorCause.UNEXPECTED_CHARACTER); + return self.withCharacter(cause, position, term, errorType); + } public enum ErrorType { /** @@ -64,18 +89,32 @@ public enum ParseError { * @return this object */ public ParseError expectedType(Token.TokenType needed) { - this.needed = Optional.of(List.of(needed)); + this.needed = Optional.of(new ArrayList<>(List.of(needed))); return this; } /** - * Attach expected token types to this error. + * Set expected token types of this error. * * @param needed the possible token types * @return this object */ public ParseError expectedTypes(Collection needed) { - this.needed = Optional.of(needed); + this.needed = Optional.of(new ArrayList<>(needed)); + return this; + } + + /** + * Add an expected token type to this error. + * + * @param needed the possible token type + * @return this object + */ + public ParseError attachExpectedType(Token.TokenType needed) { + if (this.needed.isEmpty()) { + this.needed = Optional.of(new ArrayList<>()); + } + this.needed.get().add(needed); return this; } @@ -109,9 +148,9 @@ public enum ParseError { /** * Attach a character and position to this error. * - * @param cause the character + * @param cause the character * @param position it's position - * @param term the term that is parsed + * @param term the term that is parsed * @return this object */ public ParseError withCharacter(char cause, int position, String term, ErrorType errorType) { @@ -175,7 +214,36 @@ public enum ParseError { this.errorType = Optional.of(errorType); } - ParseError() { + @Override + public String toString() { + return "ParseError{" + + "cause=" + cause + + ", needed=" + needed + + ", expected=" + expected + + ", term='" + term + '\'' + + ", wrongChar=" + wrongChar + + ", correctChar=" + correctChar + + ", position=" + position + + ", errorType=" + errorType + + '}'; + } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ParseError that = (ParseError) o; + return wrongChar == that.wrongChar && correctChar == that.correctChar && position == that.position + && causeEnum == that.causeEnum && cause.equals(that.cause) && needed.equals(that.needed) + && expected.equals(that.expected) && term.equals(that.term) && errorType.equals(that.errorType); + } + + @Override + public int hashCode() { + return Objects.hash(causeEnum, cause, needed, expected, term, wrongChar, correctChar, position, errorType); } } 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 387124e..9e13215 100644 --- a/src/main/java/edu/kit/typicalc/model/parser/TypeAssumptionParser.java +++ b/src/main/java/edu/kit/typicalc/model/parser/TypeAssumptionParser.java @@ -25,7 +25,8 @@ public class TypeAssumptionParser { */ public Result, ParseError> parse(String assumptions) { ParserState> state = new InitialState(new LinkedHashMap<>()); - LambdaLexer lexer = new LambdaLexer(cleanAssumptionText(assumptions)); + LambdaLexer lexer = new LambdaLexer( + cleanAssumptionText(assumptions), ParseError.ErrorType.TYPE_ASSUMPTION_ERROR); Optional extraToken = Optional.empty(); while (true) { Token token1; @@ -151,8 +152,8 @@ public class TypeAssumptionParser { case EOF: return new ParserResult<>(alreadyParsed); default: - return new ParserResult<>(ParseError.UNEXPECTED_TOKEN - .withToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); + return new ParserResult<>(ParseError + .unexpectedToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); } } } @@ -171,8 +172,7 @@ public class TypeAssumptionParser { if (t.getType() == TokenType.COLON) { return new ParserResult<>(new ExpectingTypeDef(alreadyParsed, var)); } else { - return new ParserResult<>(ParseError.UNEXPECTED_TOKEN - .withToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); + return new ParserResult<>(ParseError.unexpectedToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); } } } @@ -201,8 +201,8 @@ public class TypeAssumptionParser { if (typeVariables.isEmpty()) { return new ParserResult<>(new ExpectingTypeVariables(alreadyParsed, var)); } else { - return new ParserResult<>(ParseError.UNEXPECTED_TOKEN - .withToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); + return new ParserResult<>(ParseError + .unexpectedToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); } } if (state.isPresent()) { @@ -245,8 +245,8 @@ public class TypeAssumptionParser { case COMMA: return new ParserResult<>(new InitialState(alreadyParsed)); default: - return new ParserResult<>(ParseError.UNEXPECTED_TOKEN - .withToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); + return new ParserResult<>(ParseError + .unexpectedToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); } } } @@ -281,8 +281,8 @@ public class TypeAssumptionParser { return handleInnerParenthesis(t); } if (parsedType.isPresent()) { - return new ParserResult<>(ParseError.UNEXPECTED_TOKEN - .withToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); + return new ParserResult<>(ParseError + .unexpectedToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); } Type type = parseLiteral(t.getText()); // try parsing function type (see below) @@ -296,8 +296,9 @@ public class TypeAssumptionParser { return handleInnerParenthesis(t); } if (parsedType.isEmpty()) { - return new ParserResult<>(ParseError.UNEXPECTED_TOKEN - .withToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); + return new ParserResult<>(ParseError + .unexpectedToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR) + .expectedInput(ExpectedInput.TYPE)); } // parse function type state = Optional.of(new ParseTypeStateExpectArrow(typeVariableUniqueIndex).handle(t).getState()); @@ -315,6 +316,10 @@ public class TypeAssumptionParser { return new ParserResult<>(this); case RIGHT_PARENTHESIS: openParens -= 1; + if (openParens < parenthesisInitial) { // too many closed parenthesis + return new ParserResult<>(ParseError + .unexpectedToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); + } if (state.isPresent()) { return handleInner(t); } @@ -336,28 +341,42 @@ 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, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); + return new ParserResult<>(ParseError + .unexpectedToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); case COMMA: case EOF: if (state.isPresent()) { return handleInner(t).attachToken(t); } - if (stateParenthesis.isPresent() && openParens == parenthesisInitial) { - return handleInnerParenthesis(t).attachToken(t); + if (stateParenthesis.isPresent()) { + if (openParens != parenthesisInitial) { // parenthesis mismatch + // feed dummy token to inner parser to get expected tokens at this point + var it = handleInnerParenthesis( + new Token(TokenType.EQUALS, "", "", 0)) + .attachToken(t); + return it.modifyError(err -> err + .withToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR) + .attachExpectedType(TokenType.RIGHT_PARENTHESIS)); + } else { + return handleInnerParenthesis(t).attachToken(t); + } } if (parsedType.isPresent() && openParens == parenthesisInitial) { return new ParserResult<>(parsedType.get()).attachToken(t); } - return new ParserResult<>(ParseError.UNEXPECTED_TOKEN - .withToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR) + return new ParserResult<>(ParseError.unexpectedToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR) .expectedInput(ExpectedInput.TYPE)); default: if (state.isPresent()) { return handleInner(t); } - return new ParserResult<>(ParseError.UNEXPECTED_TOKEN - .withToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); + if (parsedType.isPresent()) { + return new ParserResult<>(ParseError + .unexpectedToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR) + .expectedType(TokenType.ARROW)); + } + return new ParserResult<>(ParseError + .unexpectedToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); } } @@ -434,8 +453,7 @@ public class TypeAssumptionParser { return new ParserResult<>(this); } } else { - return new ParserResult<>(ParseError.UNEXPECTED_TOKEN - .withToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); + return new ParserResult<>(ParseError.unexpectedToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); } } } @@ -456,20 +474,20 @@ public class TypeAssumptionParser { switch (t.getType()) { case VARIABLE: if (expectCommaOrDot) { - return new ParserResult<>(ParseError.UNEXPECTED_TOKEN - .withToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR) + return new ParserResult<>(ParseError + .unexpectedToken(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, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); + return new ParserResult<>(ParseError + .unexpectedToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); } int i = Integer.parseInt(input.substring(1)); TypeVariable variable = new TypeVariable(TypeVariableKind.USER_INPUT, i); if (variables.contains(variable)) { - return new ParserResult<>(ParseError.UNEXPECTED_TOKEN - .withToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); + return new ParserResult<>(ParseError + .unexpectedToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); } variable.setUniqueIndex(alreadyParsed.size()); variables.add(variable); @@ -480,8 +498,8 @@ public class TypeAssumptionParser { expectCommaOrDot = false; return new ParserResult<>(this); } else { - return new ParserResult<>(ParseError.UNEXPECTED_TOKEN - .withToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR) + return new ParserResult<>(ParseError + .unexpectedToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR) .expectedType(TokenType.VARIABLE)); } case DOT: @@ -490,18 +508,18 @@ public class TypeAssumptionParser { // parse actual type return new ParserResult<>(new ExpectingTypeDef(alreadyParsed, variables, var)); } else { - return new ParserResult<>(ParseError.UNEXPECTED_TOKEN - .withToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR) + return new ParserResult<>(ParseError + .unexpectedToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR) .expectedType(TokenType.VARIABLE)); } default: if (expectCommaOrDot) { - return new ParserResult<>(ParseError.UNEXPECTED_TOKEN - .withToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR) + return new ParserResult<>(ParseError + .unexpectedToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR) .expectedTypes(List.of(TokenType.COMMA, TokenType.DOT))); } - return new ParserResult<>(ParseError.UNEXPECTED_TOKEN - .withToken(t, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); + return new ParserResult<>(ParseError + .unexpectedToken(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 3dbe2a7..fa41282 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 @@ -32,6 +32,7 @@ public class ErrorView extends VerticalLayout implements LocaleChangeObserver { private final Paragraph hint; public ErrorView(ParseError error) { + System.out.println(error); this.error = error; VerticalLayout container = new VerticalLayout(); container.setId(ERROR_CONTENT_ID); @@ -72,7 +73,7 @@ public class ErrorView extends VerticalLayout implements LocaleChangeObserver { } else if (errorType.get() == ParseError.ErrorType.TYPE_ASSUMPTION_ERROR) { descriptionForError = "error.typeAssumptionForError"; } - switch (error) { + switch (error.getCauseEnum()) { case UNEXPECTED_TOKEN: Optional cause = error.getCause(); if (cause.isPresent()) { diff --git a/src/test/java/edu/kit/typicalc/model/parser/LambdaParserTest.java b/src/test/java/edu/kit/typicalc/model/parser/LambdaParserTest.java index b5ff6e3..218a056 100644 --- a/src/test/java/edu/kit/typicalc/model/parser/LambdaParserTest.java +++ b/src/test/java/edu/kit/typicalc/model/parser/LambdaParserTest.java @@ -6,8 +6,7 @@ import edu.kit.typicalc.util.Result; import nl.jqno.equalsverifier.EqualsVerifier; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.*; class LambdaParserTest { private static final VarTerm X = new VarTerm("x"); @@ -97,62 +96,62 @@ class LambdaParserTest { void errorHandling() { LambdaParser parser = new LambdaParser(""); ParseError error = parser.parse().unwrapError(); - assertEquals(ParseError.UNEXPECTED_TOKEN, error); + assertEquals(ParseError.ErrorCause.UNEXPECTED_TOKEN, error.getCauseEnum()); assertEquals(TokenType.EOF, error.getCause().get().getType()); parser = new LambdaParser("λx."); error = parser.parse().unwrapError(); - assertEquals(ParseError.UNEXPECTED_TOKEN, error); + assertEquals(ParseError.ErrorCause.UNEXPECTED_TOKEN, error.getCauseEnum()); assertEquals(new Token(TokenType.EOF, "", "λx.", 3), error.getCause().get()); assertEquals(ExpectedInput.TERM, error.getExpectedInput().get()); parser = new LambdaParser("x)"); error = parser.parse().unwrapError(); - assertEquals(ParseError.UNEXPECTED_TOKEN, error); + assertEquals(ParseError.ErrorCause.UNEXPECTED_TOKEN, error.getCauseEnum()); assertEquals(new Token(TokenType.RIGHT_PARENTHESIS, ")", "x)", 1), error.getCause().get()); parser = new LambdaParser("??"); - assertEquals(ParseError.UNEXPECTED_CHARACTER, parser.parse().unwrapError()); + assertEquals(ParseError.ErrorCause.UNEXPECTED_CHARACTER, parser.parse().unwrapError().getCauseEnum()); parser = new LambdaParser("aλ"); - assertEquals(ParseError.UNEXPECTED_CHARACTER, parser.parse().unwrapError()); + assertEquals(ParseError.ErrorCause.UNEXPECTED_CHARACTER, parser.parse().unwrapError().getCauseEnum()); parser = new LambdaParser("ä"); - assertEquals(ParseError.UNEXPECTED_CHARACTER, parser.parse().unwrapError()); + assertEquals(ParseError.ErrorCause.UNEXPECTED_CHARACTER, parser.parse().unwrapError().getCauseEnum()); parser = new LambdaParser("123333333333333"); - assertEquals(ParseError.UNEXPECTED_CHARACTER, parser.parse().unwrapError()); + assertEquals(ParseError.ErrorCause.UNEXPECTED_CHARACTER, parser.parse().unwrapError().getCauseEnum()); parser = new LambdaParser("x 123333333333333"); error = parser.parse().unwrapError(); - assertEquals(ParseError.UNEXPECTED_CHARACTER, error); + assertEquals(ParseError.ErrorCause.UNEXPECTED_CHARACTER, error.getCauseEnum()); assertEquals(new Token(TokenType.NUMBER, "123333333333333", "x 123333333333333", 2), error.getCause().get()); parser = new LambdaParser("λ)"); error = parser.parse().unwrapError(); - assertEquals(ParseError.UNEXPECTED_TOKEN, error); + assertEquals(ParseError.ErrorCause.UNEXPECTED_TOKEN, error.getCauseEnum()); assertEquals(new Token(TokenType.RIGHT_PARENTHESIS, ")", "λ)", 1), error.getCause().get()); parser = new LambdaParser("λx="); error = parser.parse().unwrapError(); - assertEquals(ParseError.UNEXPECTED_TOKEN, error); + assertEquals(ParseError.ErrorCause.UNEXPECTED_TOKEN, error.getCauseEnum()); assertEquals(new Token(TokenType.EQUALS, "=", "λx=", 2), error.getCause().get()); parser = new LambdaParser("λx.."); error = parser.parse().unwrapError(); - assertEquals(ParseError.UNEXPECTED_TOKEN, error); + assertEquals(ParseError.ErrorCause.UNEXPECTED_TOKEN, error.getCauseEnum()); assertEquals(new Token(TokenType.DOT, ".", "λx..", 3), error.getCause().get()); assertEquals(ExpectedInput.TERM, error.getExpectedInput().get()); parser = new LambdaParser("let ) ="); error = parser.parse().unwrapError(); - assertEquals(ParseError.UNEXPECTED_TOKEN, error); + assertEquals(ParseError.ErrorCause.UNEXPECTED_TOKEN, error.getCauseEnum()); assertEquals(new Token(TokenType.RIGHT_PARENTHESIS, ")", "let ) =", 4), error.getCause().get()); parser = new LambdaParser("let x ."); error = parser.parse().unwrapError(); - assertEquals(ParseError.UNEXPECTED_TOKEN, error); + assertEquals(ParseError.ErrorCause.UNEXPECTED_TOKEN, error.getCauseEnum()); assertEquals(new Token(TokenType.DOT, ".", "let x .", 6), error.getCause().get()); parser = new LambdaParser("let x = )"); error = parser.parse().unwrapError(); - assertEquals(ParseError.UNEXPECTED_TOKEN, error); + assertEquals(ParseError.ErrorCause.UNEXPECTED_TOKEN, error.getCauseEnum()); assertEquals(new Token(TokenType.RIGHT_PARENTHESIS, ")", "let x = )",8), error.getCause().get()); parser = new LambdaParser("let x = y )"); error = parser.parse().unwrapError(); - assertEquals(ParseError.UNEXPECTED_TOKEN, error); + assertEquals(ParseError.ErrorCause.UNEXPECTED_TOKEN, error.getCauseEnum()); assertEquals(new Token(TokenType.RIGHT_PARENTHESIS, ")", "let x = y )", 10), error.getCause().get()); parser = new LambdaParser("let x = y in )"); error = parser.parse().unwrapError(); - assertEquals(ParseError.UNEXPECTED_TOKEN, error); + assertEquals(ParseError.ErrorCause.UNEXPECTED_TOKEN, error.getCauseEnum()); assertEquals(new Token(TokenType.RIGHT_PARENTHESIS, ")", "let x = y in )", 13), error.getCause().get()); } @@ -237,13 +236,24 @@ class LambdaParserTest { assertEquals(ExpectedInput.TERM, err.getExpectedInput().get()); } + @Test + void changingErrors() { + // parse error objects should behave normally + ParseError err1 = getParseError("λx.λ"); + ParseError err2 = getParseError("λx."); + ParseError err3 = getParseError("λx.λ"); + assertEquals(err1, err3); + assertNotEquals(err2, err3); + } + @Test void equality() { EqualsVerifier.forClass(Token.class).usingGetClass().verify(); + EqualsVerifier.simple().forClass(ParseError.class).usingGetClass().verify(); } static ParseError getParseError(String term) { - LambdaParser parser = new LambdaParser(term); + var parser = new LambdaParser(term); return parser.parse().unwrapError(); } } 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 17bd733..e7e88ca 100644 --- a/src/test/java/edu/kit/typicalc/model/parser/TypeAssumptionParserTest.java +++ b/src/test/java/edu/kit/typicalc/model/parser/TypeAssumptionParserTest.java @@ -219,7 +219,7 @@ class TypeAssumptionParserTest { Result, ParseError> type = parser.parse("id: ∀ t1"); assertTrue(type.isError()); ParseError error = type.unwrapError(); - assertEquals(ParseError.UNEXPECTED_TOKEN, error); + assertEquals(ParseError.ErrorCause.UNEXPECTED_TOKEN, error.getCauseEnum()); assertEquals(Token.TokenType.EOF, error.getCause().get().getType()); Collection expected = error.getExpected().get(); assertEquals(2, expected.size()); @@ -233,7 +233,7 @@ class TypeAssumptionParserTest { Result, ParseError> type = parser.parse("id: ∀ t1, t1 : t1 -> t1"); assertTrue(type.isError()); ParseError error = type.unwrapError(); - assertEquals(ParseError.UNEXPECTED_TOKEN, error); + assertEquals(ParseError.ErrorCause.UNEXPECTED_TOKEN, error.getCauseEnum()); assertEquals(Token.TokenType.VARIABLE, error.getCause().get().getType()); assertEquals(10, error.getCause().get().getPos()); } @@ -258,25 +258,31 @@ class TypeAssumptionParserTest { @Test void errors() { - Map tests = new HashMap<>(); + Map tests = new LinkedHashMap<>(); tests.put("", - ParseError.UNEXPECTED_TOKEN.withToken(new Token(Token.TokenType.EOF, "", "", 0), - ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); - tests.put("ö", ParseError.UNEXPECTED_CHARACTER); + ParseError.unexpectedToken(new Token(Token.TokenType.EOF, "", "type1:", 6), + ParseError.ErrorType.TYPE_ASSUMPTION_ERROR) + .expectedInput(ExpectedInput.TYPE) + .expectedType(Token.TokenType.UNIVERSAL_QUANTIFIER)); + tests.put("ö", ParseError.unexpectedCharacter2('ö', 6, "type1:ö", ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); tests.put("(x", - ParseError.UNEXPECTED_TOKEN.withToken(new Token(Token.TokenType.EOF, "", "(x", 2), - ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); + ParseError.unexpectedToken(new Token(Token.TokenType.EOF, "", "type1:(x", 8), + ParseError.ErrorType.TYPE_ASSUMPTION_ERROR) + .expectedTypes(List.of(Token.TokenType.ARROW, Token.TokenType.RIGHT_PARENTHESIS))); tests.put("-> x", - ParseError.UNEXPECTED_TOKEN.withToken(new Token(Token.TokenType.ARROW, "->", "-> x", 0), - ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); + ParseError.unexpectedToken(new Token(Token.TokenType.ARROW, "->", "type1:-> x", 6), + ParseError.ErrorType.TYPE_ASSUMPTION_ERROR) + .expectedInput(ExpectedInput.TYPE) + .expectedType(Token.TokenType.UNIVERSAL_QUANTIFIER) + ); tests.put("x 11", - 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.unexpectedToken(new Token(Token.TokenType.NUMBER, "11", "type1:x 11", 8), + ParseError.ErrorType.TYPE_ASSUMPTION_ERROR) + .expectedType(Token.TokenType.ARROW)); + tests.put("x )", ParseError.unexpectedToken(new Token(Token.TokenType.RIGHT_PARENTHESIS, ")", "type1:x )", 8), + ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); + tests.put("x -> (x) )", ParseError.unexpectedToken(new Token(Token.TokenType.RIGHT_PARENTHESIS, ")", "type1:x -> (x) )", 15), ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); - tests.put("x -> (x) )", ParseError.UNEXPECTED_TOKEN - .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()); @@ -289,12 +295,12 @@ class TypeAssumptionParserTest { TypeAssumptionParser parser = new TypeAssumptionParser(); Result, ParseError> type = parser.parse("föhn: int"); assertTrue(type.isError()); - assertEquals(ParseError.UNEXPECTED_CHARACTER, type.unwrapError()); + assertEquals(ParseError.ErrorCause.UNEXPECTED_CHARACTER, type.unwrapError().getCauseEnum()); assertEquals(1, type.unwrapError().getPosition()); parser = new TypeAssumptionParser(); type = parser.parse("1typ:int"); assertTrue(type.isError()); - assertEquals(ParseError.UNEXPECTED_TOKEN, type.unwrapError()); + assertEquals(ParseError.ErrorCause.UNEXPECTED_TOKEN, type.unwrapError().getCauseEnum()); assertEquals(0, type.unwrapError().getPosition()); }