Add base method for final parsing and reverse checking

This commit is contained in:
Flowsqy 2022-02-23 00:23:24 +01:00
parent b8fc15a6a8
commit 42f8ad4744
4 changed files with 182 additions and 7 deletions

View File

@ -0,0 +1,22 @@
package de.epiceric.shopchest.config.hologram.condition;
import java.util.function.Function;
public class ProviderCondition<P> implements Condition<P> {
private final Function<P, Boolean> booleanProvider;
public ProviderCondition(Function<P, Boolean> booleanProvider) {
this.booleanProvider = booleanProvider;
}
@Override
public boolean test(P values) {
return booleanProvider.apply(values);
}
@Override
public String toString() {
return booleanProvider.toString();
}
}

View File

@ -0,0 +1,60 @@
package de.epiceric.shopchest.config.hologram.parser;
import java.util.Iterator;
public class Chain<T> {
private Chain<T> before;
private Chain<T> after;
private T value;
public Chain(T value) {
this.value = value;
}
public Chain(Chain<T> before, Chain<T> after, T value) {
this.before = before;
this.after = after;
this.value = value;
}
public static <T> Chain<T> getChain(Iterable<T> iterable) {
Chain<T> first = null;
Chain<T> previous = null;
final Iterator<T> iterator = iterable.iterator();
if (iterator.hasNext()) {
first = previous = new Chain<>(iterator.next());
}
while (iterator.hasNext()) {
final Chain<T> chain = new Chain<>(previous, null, iterator.next());
previous.setAfter(chain);
previous = chain;
}
return first;
}
public Chain<T> getBefore() {
return before;
}
public void setBefore(Chain<T> before) {
this.before = before;
}
public Chain<T> getAfter() {
return after;
}
public void setAfter(Chain<T> after) {
this.after = after;
}
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}

View File

@ -1,9 +1,12 @@
package de.epiceric.shopchest.config.hologram.parser;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import de.epiceric.shopchest.config.hologram.condition.Condition;
import de.epiceric.shopchest.config.hologram.condition.ProviderCondition;
import de.epiceric.shopchest.config.hologram.condition.ReverseCondition;
import de.epiceric.shopchest.config.hologram.provider.MapProvider;
import java.util.*;
import java.util.function.Function;
public class FormatParser {
@ -152,14 +155,15 @@ public class FormatParser {
final Counter counter = new Counter();
final List<Token<?>> resolvedTokens = resolveNode(tokenIterator, counter).getValue();
if (counter.get() > 0) {
// TODO create a custom exception
throw new RuntimeException("Start unit '(' without closing it");
} else if (counter.get() < 0) {
// TODO create a custom exception
throw new RuntimeException("End unit ')' without starting it");
}
return resolvedTokens;
}
@SuppressWarnings("unchecked")
public Token<List<Token<?>>> resolveNode(Iterator<Token<?>> tokens, Counter counter) {
final List<Token<?>> nodeTokens = new LinkedList<>();
while (tokens.hasNext()) {
@ -177,13 +181,97 @@ public class FormatParser {
// TODO Create a custom exception
throw new RuntimeException("Empty unit '( )'");
}
// Extract if there is useless parenthesis
if (nodeTokens.size() == 1) {
final Token<?> token = nodeTokens.get(0);
if (token.getType() == Token.NODE) {
return (Token<List<Token<?>>>) token;
final Token<List<Token<?>>> typedToken = getTypedNoteToken(token);
if (typedToken != null) {
return typedToken;
}
}
return new Token<>(Token.NODE, nodeTokens);
}
@SuppressWarnings("unchecked")
private Token<List<Token<?>>> getTypedNoteToken(Token<?> token) {
if (token.getType() == Token.NODE) {
return (Token<List<Token<?>>>) token;
}
return null;
}
public <P> Token<?> createFunctions(Iterable<Token<?>> tokens, Function<String, P> providerFunction, Map<P, Class<?>> providerTypes) {
Chain<Token<?>> tokensChain = Chain.getChain(tokens);
// Node
Chain<Token<?>> nodeChain = tokensChain;
while (nodeChain != null) {
final Token<?> token = nodeChain.getValue();
final Token<List<Token<?>>> typedToken = getTypedNoteToken(token);
if (typedToken != null) {
nodeChain.setValue(createFunctions(typedToken.getValue(), providerFunction, providerTypes));
}
nodeChain = nodeChain.getAfter();
}
// Reverse
Chain<Token<?>> reverseChain = tokensChain;
while (reverseChain != null) {
// Reverse check
if (reverseChain.getValue().getType() == Token.REVERSE) {
final Chain<Token<?>> nextChain = reverseChain.getAfter();
// Next check
if (nextChain == null) {
// TODO Create custom exceptions
throw new RuntimeException("Try to reverse a condition that does not exist");
}
final Token<?> nextToken = nextChain.getValue();
// Create reversed
final Condition<?> reversed;
final boolean isValue = nextToken.getType() == Token.VALUE;
if (isValue || nextToken.getType() == Token.VALUE) {
if (isValue) {
final String value = (String) nextToken.getValue();
final P provided = providerFunction.apply(value);
// It uses a valid provided value
if (provided != null) {
final Class<?> providedClass = providerTypes.get(provided);
// The provided value is a boolean
if (providedClass == Boolean.class) {
reversed = new ReverseCondition<>(new ProviderCondition<>(
new MapProvider.BooleanMapProvider<>(provided)
));
} else {
throw new RuntimeException("'" + value + "' can not be used as a boolean");
}
} else {
throw new RuntimeException("'" + value + "' does not exist");
}
}
// It's a condition
else {
reversed = new ReverseCondition<>((Condition<?>) nextToken.getValue());
}
} else {
throw new RuntimeException("Try to reverse something that does not represent a condition");
}
// Set the chain
final Chain<Token<?>> afterConditionChain = nextChain.getAfter();
reverseChain.setValue(new Token<>(Token.CONDITION, reversed));
if (afterConditionChain != null) {
afterConditionChain.setBefore(reverseChain);
reverseChain.setAfter(afterConditionChain);
} else {
reverseChain.setAfter(null);
}
}
reverseChain = reverseChain.getAfter();
}
return tokensChain == null ? null : tokensChain.getValue();
}
}

View File

@ -1,5 +1,8 @@
package de.epiceric.shopchest.config.hologram.parser;
import de.epiceric.shopchest.config.hologram.calculation.Calculation;
import de.epiceric.shopchest.config.hologram.condition.Condition;
import java.util.List;
public class Token<T> {
@ -14,6 +17,8 @@ public class Token<T> {
public final static TokenType<LogicOperator> LOGIC_OPERATOR = new TokenType<>("Logic operator");
public final static TokenType<CalculationOperator> CALCULATION_OPERATOR = new TokenType<>("Calculation operator");
public final static TokenType<List<Token<?>>> NODE = new TokenType<>("Node");
public final static TokenType<Calculation<?>> CALCULATION = new TokenType<>("Calculation");
public final static TokenType<Condition<?>> CONDITION = new TokenType<>("Condition");
private final TokenType<T> type;
private final T value;