Improved documentation for parser and improved error messages

see #15
This commit is contained in:
uogau 2021-08-09 18:05:45 +02:00
parent c3deae0bcc
commit 9797d13041
7 changed files with 79 additions and 5 deletions

View File

@ -0,0 +1,8 @@
package edu.kit.typicalc.model.parser;
public enum AdditionalInformation {
/**
* Duplicate VarType after Universal Quantifier.
*/
DUPLICATETYPE
}

View File

@ -12,5 +12,9 @@ public enum ExpectedInput {
/** /**
* Any kind of type. * Any kind of type.
*/ */
TYPE TYPE,
/**
* // t[0-9]+
*/
VARTYPE
} }

View File

@ -62,6 +62,7 @@ public final class ParseError {
private Optional<Token> cause = Optional.empty(); private Optional<Token> cause = Optional.empty();
private Optional<Collection<Token.TokenType>> needed = Optional.empty(); private Optional<Collection<Token.TokenType>> needed = Optional.empty();
private Optional<ExpectedInput> expected = Optional.empty(); private Optional<ExpectedInput> expected = Optional.empty();
private Optional<AdditionalInformation> additional = Optional.empty();
private String term = ""; private String term = "";
private char wrongChar = '\0'; private char wrongChar = '\0';
private char correctChar = '\0'; private char correctChar = '\0';
@ -93,6 +94,17 @@ public final class ParseError {
return this; return this;
} }
/**
* Attach additional information to this error.
*
* @param additional the additional information
* @return this object
*/
public ParseError additionalInformation(AdditionalInformation additional) {
this.additional = Optional.of(additional);
return this;
}
/** /**
* Set expected token types of this error. * Set expected token types of this error.
* *
@ -210,6 +222,13 @@ public final class ParseError {
return errorType; return errorType;
} }
/**
* @return the additional information
*/
public Optional<AdditionalInformation> getAdditionalInformation() {
return additional;
}
protected void setErrorType(ErrorType errorType) { protected void setErrorType(ErrorType errorType) {
this.errorType = Optional.of(errorType); this.errorType = Optional.of(errorType);
} }

View File

@ -10,6 +10,14 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
/** /**
* Parser for type assumptions. * Parser for type assumptions.
* Parses according to the following grammar:
*
* TypeEnvironment --> ɛ | TypeAbstraction, TypeEnvironment | TypeAbstraction
* TypeAbstraction --> Variable | Type
* Type --> VarType.SingleType | SingleType
* SingleType --> SimpleType Rest
* SimpleType --> Variable | (SingleType)
* Rest --> ɛ | -> SingleType
*/ */
public class TypeAssumptionParser { public class TypeAssumptionParser {
@ -47,14 +55,14 @@ public class TypeAssumptionParser {
public Result<Map<VarTerm, TypeAbstraction>, ParseError> parse(String assumptions) { public Result<Map<VarTerm, TypeAbstraction>, ParseError> parse(String assumptions) {
lexer = new LambdaLexer( lexer = new LambdaLexer(
cleanAssumptionText(assumptions), ParseError.ErrorType.TYPE_ASSUMPTION_ERROR); cleanAssumptionText(assumptions), ParseError.ErrorType.TYPE_ASSUMPTION_ERROR);
return parseTU(); return parseTE();
} }
/** /**
* parses Type Environment * parses Type Environment
* @return if successful, a map of the type assumptions, otherwise an error * @return if successful, a map of the type assumptions, otherwise an error
*/ */
public Result<Map<VarTerm, TypeAbstraction>, ParseError> parseTU() { public Result<Map<VarTerm, TypeAbstraction>, ParseError> parseTE() {
HashMap<VarTerm, TypeAbstraction> map = new HashMap<>(); HashMap<VarTerm, TypeAbstraction> map = new HashMap<>();
while (true) { while (true) {
Result<Token, ParseError> nextLexerToken = lexer.nextToken(); Result<Token, ParseError> nextLexerToken = lexer.nextToken();
@ -115,6 +123,11 @@ public class TypeAssumptionParser {
return new Result<>(new MapEntry<>(term, result.unwrap())); return new Result<>(new MapEntry<>(term, result.unwrap()));
} }
/**
* Parses a Type
* @return if successful a type abstraction, otherwise an error.
*/
public Result<TypeAbstraction, ParseError> parseType() { public Result<TypeAbstraction, ParseError> parseType() {
Result<Token, ParseError> nextLexerToken = lexer.nextToken(); Result<Token, ParseError> nextLexerToken = lexer.nextToken();
if (nextLexerToken.isError()) { if (nextLexerToken.isError()) {
@ -139,7 +152,8 @@ public class TypeAssumptionParser {
String input = currentToken.getText(); String input = currentToken.getText();
if (!TYPE_VARIABLE_PATTERN.matcher(input).matches()) { if (!TYPE_VARIABLE_PATTERN.matcher(input).matches()) {
return new Result<>(null, return new Result<>(null,
ParseError.unexpectedToken(currentToken, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); ParseError.unexpectedToken(currentToken, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)
.expectedInput(ExpectedInput.VARTYPE));
} }
int i = Integer.parseInt(input.substring(1)); int i = Integer.parseInt(input.substring(1));
TypeVariable v = new TypeVariable(TypeVariableKind.USER_INPUT, i); TypeVariable v = new TypeVariable(TypeVariableKind.USER_INPUT, i);
@ -148,7 +162,8 @@ public class TypeAssumptionParser {
for (TypeVariable var : quantifiedVariables) { for (TypeVariable var : quantifiedVariables) {
if (var.equals(v)) { if (var.equals(v)) {
return new Result<>(null, return new Result<>(null,
ParseError.unexpectedToken(currentToken, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)); ParseError.unexpectedToken(currentToken, ParseError.ErrorType.TYPE_ASSUMPTION_ERROR)
.additionalInformation(AdditionalInformation.DUPLICATETYPE));
} }
} }
quantifiedVariables.add(v); quantifiedVariables.add(v);
@ -190,6 +205,10 @@ public class TypeAssumptionParser {
return new Result<>(new TypeAbstraction(result.unwrap(), quantifiedVariables)); return new Result<>(new TypeAbstraction(result.unwrap(), quantifiedVariables));
} }
/**
* parses a single Type
* @return if successful a type, otherwise an error
*/
public Result<Type, ParseError> parseSingleType() { public Result<Type, ParseError> parseSingleType() {
Result<Type, ParseError> result = parseSimpleType(); Result<Type, ParseError> result = parseSimpleType();
@ -216,6 +235,10 @@ public class TypeAssumptionParser {
} }
} }
/**
* parses a simple type
* @return if successful a type, otherwise an error
*/
public Result<Type, ParseError> parseSimpleType() { public Result<Type, ParseError> parseSimpleType() {
if (currentToken.getType() == Token.TokenType.VARIABLE) { if (currentToken.getType() == Token.TokenType.VARIABLE) {
Type type = parseLiteral(currentToken.getText()); Type type = parseLiteral(currentToken.getText());
@ -244,6 +267,10 @@ public class TypeAssumptionParser {
ParseError.ErrorType.TYPE_ASSUMPTION_ERROR).expectedInput(ExpectedInput.TYPE)); ParseError.ErrorType.TYPE_ASSUMPTION_ERROR).expectedInput(ExpectedInput.TYPE));
} }
/**
* parses the rest of a single type
* @return if successful a type or an empty optional, otherwise an error
*/
public Result<Optional<Type>, ParseError> parseRest() { public Result<Optional<Type>, ParseError> parseRest() {
switch (currentToken.getType()) { switch (currentToken.getType()) {
case ARROW: case ARROW:

View File

@ -10,6 +10,7 @@ import com.vaadin.flow.component.html.Pre;
import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.i18n.LocaleChangeEvent; import com.vaadin.flow.i18n.LocaleChangeEvent;
import com.vaadin.flow.i18n.LocaleChangeObserver; import com.vaadin.flow.i18n.LocaleChangeObserver;
import edu.kit.typicalc.model.parser.AdditionalInformation;
import edu.kit.typicalc.model.parser.ExpectedInput; import edu.kit.typicalc.model.parser.ExpectedInput;
import edu.kit.typicalc.model.parser.ParseError; import edu.kit.typicalc.model.parser.ParseError;
import edu.kit.typicalc.model.parser.Token; import edu.kit.typicalc.model.parser.Token;
@ -130,6 +131,15 @@ public class ErrorView extends VerticalLayout implements LocaleChangeObserver {
getTranslation("error.expectedToken", correct)))); getTranslation("error.expectedToken", correct))));
} }
// state more additional information, if available
Optional<AdditionalInformation> moreAdditionalInformation = error.getAdditionalInformation();
if (moreAdditionalInformation.isPresent()) {
AdditionalInformation e = moreAdditionalInformation.get();
additionalInformation.add(new Span(new Pre(
getTranslation("error.additionalInformation",
getTranslation("additionalInformation." + e)))));
}
return new Div(additionalInformation); return new Div(additionalInformation);
} }

View File

@ -110,6 +110,7 @@ error.termForError=Term:\u0020
error.typeAssumptionForError=Typannahme:\u0020 error.typeAssumptionForError=Typannahme:\u0020
error.wrongCharacter=Falsches Zeichen:\u0020 error.wrongCharacter=Falsches Zeichen:\u0020
error.expectedToken=Erwartet: {0} error.expectedToken=Erwartet: {0}
error.additionalInformation = Information: {0}
error.hint=Die Grammatiken, die die korrekte Syntax eines Terms und der Typannahmen beschreiben, \ error.hint=Die Grammatiken, die die korrekte Syntax eines Terms und der Typannahmen beschreiben, \
sind auch über das Info-Symbol zu erreichen. sind auch über das Info-Symbol zu erreichen.
tokentype.UNIVERSAL_QUANTIFIER=Allquantor tokentype.UNIVERSAL_QUANTIFIER=Allquantor
@ -128,6 +129,8 @@ tokentype.COLON=:
tokentype.EQUALS== tokentype.EQUALS==
tokentype.ARROW=-> tokentype.ARROW=->
tokentype.EOF=Ende der Eingabe tokentype.EOF=Ende der Eingabe
expectedinput.VARTYPE= Variable der Form t[0-9]+
additionalInformation.DUPLICATETYPE= Duplikat
expectedinput.TERM=beliebiger Term expectedinput.TERM=beliebiger Term
expectedinput.TYPE=beliebiger Typ expectedinput.TYPE=beliebiger Typ
root.or=oder root.or=oder

View File

@ -102,6 +102,7 @@ error.wrongCharacter=Wrong character:\u0020
error.termForError=Term:\u0020 error.termForError=Term:\u0020
error.typeAssumptionForError=Type assumption:\u0020 error.typeAssumptionForError=Type assumption:\u0020
error.expectedToken=Expected: {0} error.expectedToken=Expected: {0}
error.additionalInformation = Information: {0}
error.hint=The grammars describing the correct syntax of a term or a type assumption can also be reached \ error.hint=The grammars describing the correct syntax of a term or a type assumption can also be reached \
via the info icon. via the info icon.
tokentype.UNIVERSAL_QUANTIFIER=universal quantifier tokentype.UNIVERSAL_QUANTIFIER=universal quantifier
@ -120,6 +121,8 @@ tokentype.COLON=:
tokentype.EQUALS== tokentype.EQUALS==
tokentype.ARROW=-> tokentype.ARROW=->
tokentype.EOF=End of input tokentype.EOF=End of input
additionalInformation.DUPLICATETYPE= Duplicate
expectedinput.VARTYPE= Variable of the form t[0-9]+
expectedinput.TERM=any lambda term expectedinput.TERM=any lambda term
expectedinput.TYPE=any type expectedinput.TYPE=any type
root.or=or root.or=or