mirror of
https://gitlab.kit.edu/uskyk/typicalc.git
synced 2024-11-08 10:20:41 +00:00
Codestyle TypeAssumptionParser
This commit is contained in:
parent
9c8897d436
commit
a4224f4263
@ -54,7 +54,7 @@ public enum ParseError {
|
||||
/**
|
||||
* @return the token associated with this error, or null if none
|
||||
*/
|
||||
public Token getCause() { // TODO: document
|
||||
public Token getCause() {
|
||||
return cause;
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,13 @@
|
||||
package edu.kit.typicalc.model.parser;
|
||||
|
||||
import edu.kit.typicalc.model.parser.Token.TokenType;
|
||||
import edu.kit.typicalc.model.term.VarTerm;
|
||||
import edu.kit.typicalc.model.term.*;
|
||||
import edu.kit.typicalc.model.type.*;
|
||||
import edu.kit.typicalc.util.Result;
|
||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@ -20,6 +19,9 @@ public class TypeAssumptionParser {
|
||||
public static final Pattern TYPE_NAME_PATTERN = Pattern.compile("[a-zA-Z][a-zA-Z0-9]*");
|
||||
private static final Pattern TYPE_VARIABLE_PATTERN = Pattern.compile("t(\\d+)");
|
||||
|
||||
private static final Set<TokenType> END_TOKENS
|
||||
= EnumSet.of(TokenType.ARROW, TokenType.RIGHT_PARENTHESIS, TokenType.EOF);
|
||||
|
||||
/**
|
||||
* Parse the given type assumptions.
|
||||
*
|
||||
@ -53,73 +55,67 @@ public class TypeAssumptionParser {
|
||||
}
|
||||
|
||||
private Result<Pair<Type, Integer>, ParseError> parseType(LambdaLexer lexer, int parenCount) {
|
||||
Result<Token, ParseError> token = lexer.nextToken();
|
||||
if (token.isError()) {
|
||||
return new Result<>(token);
|
||||
}
|
||||
Token t = token.unwrap();
|
||||
Type type;
|
||||
Type type = null;
|
||||
int removedParens = 0;
|
||||
switch (t.getType()) {
|
||||
case LEFT_PARENTHESIS:
|
||||
Result<Pair<Type, Integer>, ParseError> type2 = parseType(lexer, 1);
|
||||
if (type2.isError()) {
|
||||
return type2;
|
||||
}
|
||||
type = type2.unwrap().getLeft();
|
||||
removedParens += type2.unwrap().getRight() - 1;
|
||||
if (parenCount - removedParens < 0) {
|
||||
return new Result<>(new ImmutablePair<>(type, removedParens));
|
||||
}
|
||||
break;
|
||||
case VARIABLE:
|
||||
Matcher typeVariableMatcher = TYPE_VARIABLE_PATTERN.matcher(t.getText());
|
||||
if (typeVariableMatcher.matches()) {
|
||||
int typeVariableIndex = Integer.parseInt(typeVariableMatcher.group(1));
|
||||
type = new TypeVariable(TypeVariableKind.USER_INPUT, typeVariableIndex);
|
||||
} else {
|
||||
type = new NamedType(t.getText());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return new Result<>(null, ParseError.UNEXPECTED_TOKEN.withToken(t));
|
||||
}
|
||||
while (true) {
|
||||
token = lexer.nextToken();
|
||||
Result<Token, ParseError> token = lexer.nextToken();
|
||||
if (token.isError()) {
|
||||
return new Result<>(token);
|
||||
}
|
||||
t = token.unwrap();
|
||||
if (t.getType() == TokenType.RIGHT_PARENTHESIS) {
|
||||
removedParens += 1;
|
||||
if (parenCount - removedParens < 0) {
|
||||
Token t = token.unwrap();
|
||||
Result<Type, ParseError> typeResult = null;
|
||||
switch (t.getType()) {
|
||||
case LEFT_PARENTHESIS:
|
||||
Result<Pair<Type, Integer>, ParseError> type2 = parseType(lexer, 1);
|
||||
typeResult = type2.map(Pair::getLeft);
|
||||
removedParens += type2.map(Pair::getRight).unwrapOr(1) - 1;
|
||||
break;
|
||||
case VARIABLE:
|
||||
type = parseLiteral(t.getText());
|
||||
break;
|
||||
case RIGHT_PARENTHESIS:
|
||||
removedParens += 1;
|
||||
break;
|
||||
case ARROW:
|
||||
if (type == null) {
|
||||
return new Result<>(null, ParseError.UNEXPECTED_TOKEN.withToken(t));
|
||||
}
|
||||
Result<Pair<Type, Integer>, ParseError> nextType = parseType(lexer, parenCount);
|
||||
final Type left = type;
|
||||
typeResult = nextType.map(Pair::getLeft).map(right -> new FunctionType(left, right));
|
||||
removedParens += nextType.map(Pair::getRight).unwrapOr(0);
|
||||
break;
|
||||
case EOF:
|
||||
break;
|
||||
default:
|
||||
return new Result<>(null, ParseError.UNEXPECTED_TOKEN.withToken(t));
|
||||
} else if (parenCount - removedParens == 0) {
|
||||
return new Result<>(new ImmutablePair<>(type, removedParens));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (t.getType() == TokenType.EOF) {
|
||||
if (parenCount - removedParens > 0) {
|
||||
return new Result<>(null, ParseError.TOO_FEW_TOKENS);
|
||||
} else {
|
||||
return new Result<>(new ImmutablePair<>(type, removedParens));
|
||||
}
|
||||
if (typeResult != null && typeResult.isError()) {
|
||||
return new Result<>(typeResult);
|
||||
}
|
||||
if (t.getType() != TokenType.ARROW) {
|
||||
return new Result<>(null, ParseError.UNEXPECTED_TOKEN.withToken(t));
|
||||
type = typeResult != null ? typeResult.unwrap() : type;
|
||||
if (type == null) {
|
||||
return new Result<>(null, ParseError.TOO_FEW_TOKENS);
|
||||
}
|
||||
Result<Pair<Type, Integer>, ParseError> nextType = parseType(lexer, parenCount);
|
||||
if (nextType.isError()) {
|
||||
return nextType;
|
||||
}
|
||||
type = new FunctionType(type, nextType.unwrap().getLeft());
|
||||
removedParens += nextType.unwrap().getRight();
|
||||
if (parenCount - removedParens < 0) {
|
||||
return new Result<>(null, ParseError.UNEXPECTED_TOKEN.withToken(t));
|
||||
} else if (parenCount - removedParens == 0) {
|
||||
return new Result<>(new ImmutablePair<>(type, removedParens));
|
||||
} else if (END_TOKENS.contains(t.getType())) {
|
||||
if (parenCount - removedParens == 0) {
|
||||
return new Result<>(new ImmutablePair<>(type, removedParens));
|
||||
} else {
|
||||
return new Result<>(null, ParseError.TOO_FEW_TOKENS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Type parseLiteral(String text) {
|
||||
Matcher typeVariableMatcher = TYPE_VARIABLE_PATTERN.matcher(text);
|
||||
if (typeVariableMatcher.matches()) {
|
||||
int typeVariableIndex = Integer.parseInt(typeVariableMatcher.group(1));
|
||||
return new TypeVariable(TypeVariableKind.USER_INPUT, typeVariableIndex);
|
||||
} else {
|
||||
return new NamedType(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package edu.kit.typicalc.util;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Can be a value of type T or an error of type E (if the computation failed).
|
||||
@ -77,6 +78,13 @@ public class Result<T, E> {
|
||||
return value;
|
||||
}
|
||||
|
||||
public T unwrapOr(T alternative) {
|
||||
if (value == null) {
|
||||
return alternative;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the result contains an error, returns that error.
|
||||
* Otherwise an IllegalStateException is thrown.
|
||||
@ -91,6 +99,10 @@ public class Result<T, E> {
|
||||
return error;
|
||||
}
|
||||
|
||||
public <U> Result<U, E> map(Function<T, U> mapping) {
|
||||
return new Result<>(value != null ? mapping.apply(value) : null, error);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (isOk()) {
|
||||
|
@ -197,8 +197,10 @@ class TypeAssumptionParserTest {
|
||||
@Test
|
||||
void errors() {
|
||||
Map<String, ParseError> tests = new HashMap<>();
|
||||
tests.put("", ParseError.TOO_FEW_TOKENS);
|
||||
tests.put("ö", ParseError.UNEXPECTED_CHARACTER);
|
||||
tests.put("(x", ParseError.TOO_FEW_TOKENS);
|
||||
tests.put("-> x", ParseError.UNEXPECTED_TOKEN.withToken(new Token(Token.TokenType.ARROW, "->", 0)));
|
||||
tests.put("x 11", ParseError.UNEXPECTED_TOKEN.withToken(new Token(Token.TokenType.NUMBER, "11", 2)));
|
||||
tests.put("x )", ParseError.UNEXPECTED_TOKEN.withToken(new Token(Token.TokenType.RIGHT_PARENTHESIS, ")", 2)));
|
||||
tests.put("x -> (x) )", ParseError.UNEXPECTED_TOKEN
|
||||
@ -208,6 +210,9 @@ class TypeAssumptionParserTest {
|
||||
Result<Map<VarTerm, TypeAbstraction>, ParseError> type = parser.parse(Map.of("type1", entry.getKey()));
|
||||
assertTrue(type.isError());
|
||||
assertEquals(entry.getValue(), type.unwrapError());
|
||||
if (entry.getValue().getCause().getPos() != -1) {
|
||||
assertEquals(entry.getValue().getCause(), type.unwrapError().getCause());
|
||||
}
|
||||
}
|
||||
TypeAssumptionParser parser = new TypeAssumptionParser();
|
||||
Result<Map<VarTerm, TypeAbstraction>, ParseError> type = parser.parse(Map.of("föhn", "int"));
|
||||
|
Loading…
Reference in New Issue
Block a user