Improve and fix unit detection, add nodes

This commit is contained in:
Flowsqy 2022-02-22 19:53:57 +01:00
parent e2f4afde4b
commit b8fc15a6a8
3 changed files with 171 additions and 106 deletions

View File

@ -0,0 +1,29 @@
package de.epiceric.shopchest.config.hologram.parser;
public class Counter {
private int value;
public Counter() {
this(0);
}
public Counter(int value) {
this.value = value;
}
public int get() {
return value;
}
public Counter increment() {
value++;
return this;
}
public Counter decrement() {
value--;
return this;
}
}

View File

@ -1,5 +1,7 @@
package de.epiceric.shopchest.config.hologram.parser;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@ -39,118 +41,149 @@ public class FormatParser {
continue;
}
final boolean isSpace = currentChar == ' ';
final boolean isOpenParenthesis = currentChar == '(';
final boolean isCloseParenthesis = currentChar == ')';
final boolean isLastChar = index + 1 >= chars.length;
// Handle specific token
if (
isSpace ||
isOpenParenthesis ||
isCloseParenthesis ||
isLastChar
) {
if (isLastChar) {
// Add the last char only if it's the last (otherwise it will be skipped)
currentToken.append(currentChar);
}
// If it's empty, don't need to add a token
if (currentToken.length() == 0) {
continue;
}
final String stringToken = currentToken.toString();
// Double detection
try {
final double doubleValue = Double.parseDouble(stringToken);
tokens.add(new Token<>(Token.DOUBLE, doubleValue));
// Duplicate due to the double detection with exception
// Reset the specific token
// Unit detection
if (currentChar == '(') {
final Token<?> token = getToken(currentToken);
if (token != null) {
tokens.add(token);
currentToken = new StringBuilder();
// Unit detection
if (isOpenParenthesis) {
tokens.add(new Token<>(Token.BEGIN_UNIT, null));
} else if (isCloseParenthesis) {
tokens.add(new Token<>(Token.END_UNIT, null));
}
continue;
} catch (Exception ignored) {
}
// Operator detection
final Token<?> token;
switch (stringToken) {
// Calculation
case "+":
token = new Token<>(Token.CALCULATION_OPERATOR, Token.CalculationOperator.ADDITION);
break;
case "-":
token = new Token<>(Token.CALCULATION_OPERATOR, Token.CalculationOperator.SUBTRACTION);
break;
case "*":
token = new Token<>(Token.CALCULATION_OPERATOR, Token.CalculationOperator.MULTIPLICATION);
break;
case "/":
token = new Token<>(Token.CALCULATION_OPERATOR, Token.CalculationOperator.DIVISION);
break;
case "%":
token = new Token<>(Token.CALCULATION_OPERATOR, Token.CalculationOperator.MODULO);
break;
// Logic
case "&&":
token = new Token<>(Token.LOGIC_OPERATOR, Token.LogicOperator.AND);
break;
case "||":
token = new Token<>(Token.LOGIC_OPERATOR, Token.LogicOperator.OR);
break;
// Condition
case "==":
token = new Token<>(Token.CONDITION_OPERATOR, Token.ConditionOperator.EQUAL);
break;
case "!=":
token = new Token<>(Token.CONDITION_OPERATOR, Token.ConditionOperator.NOT_EQUAL);
break;
case ">":
token = new Token<>(Token.CONDITION_OPERATOR, Token.ConditionOperator.GREATER);
break;
case "<":
token = new Token<>(Token.CONDITION_OPERATOR, Token.ConditionOperator.LESS);
break;
case ">=":
token = new Token<>(Token.CONDITION_OPERATOR, Token.ConditionOperator.GREATER_OR_EQUAL);
break;
case "<=":
token = new Token<>(Token.CONDITION_OPERATOR, Token.ConditionOperator.LESS_OR_EQUAL);
break;
// Boolean
default:
token = new Token<>(Token.BOOLEAN, stringToken);
tokens.add(new Token<>(Token.BEGIN_UNIT, null));
} else if (currentChar == ')') {
final Token<?> token = getToken(currentToken);
if (token != null) {
tokens.add(token);
currentToken = new StringBuilder();
}
tokens.add(token);
// Reset the specific token
currentToken = new StringBuilder();
// Unit detection
if (isOpenParenthesis) {
tokens.add(new Token<>(Token.BEGIN_UNIT, null));
} else if (isCloseParenthesis) {
tokens.add(new Token<>(Token.END_UNIT, null));
tokens.add(new Token<>(Token.END_UNIT, null));
} else if (currentChar == ' ') {
final Token<?> token = getToken(currentToken);
if (token != null) {
tokens.add(token);
currentToken = new StringBuilder();
}
continue;
} else if (index + 1 >= chars.length) {
// Add the last char only if it's the last (otherwise it will be skipped)
currentToken.append(currentChar);
final Token<?> token = getToken(currentToken);
if (token != null) {
tokens.add(token);
currentToken = new StringBuilder();
}
} else {
// Add the char to currentToken to handle specific token
currentToken.append(currentChar);
}
// Add the char to currentToken to handle specific token
currentToken.append(currentChar);
}
return tokens;
return new ArrayList<>(tokens);
}
public Token<?> getToken(StringBuilder currentToken) {
// If it's empty, don't need to add a token
if (currentToken.length() == 0) {
return null;
}
final String stringToken = currentToken.toString();
// Double detection
try {
final double doubleValue = Double.parseDouble(stringToken);
return new Token<>(Token.DOUBLE, doubleValue);
} catch (Exception ignored) {
}
// Operator detection
final Token<?> token;
switch (stringToken) {
// Calculation
case "+":
token = new Token<>(Token.CALCULATION_OPERATOR, Token.CalculationOperator.ADDITION);
break;
case "-":
token = new Token<>(Token.CALCULATION_OPERATOR, Token.CalculationOperator.SUBTRACTION);
break;
case "*":
token = new Token<>(Token.CALCULATION_OPERATOR, Token.CalculationOperator.MULTIPLICATION);
break;
case "/":
token = new Token<>(Token.CALCULATION_OPERATOR, Token.CalculationOperator.DIVISION);
break;
case "%":
token = new Token<>(Token.CALCULATION_OPERATOR, Token.CalculationOperator.MODULO);
break;
// Logic
case "&&":
token = new Token<>(Token.LOGIC_OPERATOR, Token.LogicOperator.AND);
break;
case "||":
token = new Token<>(Token.LOGIC_OPERATOR, Token.LogicOperator.OR);
break;
// Condition
case "==":
token = new Token<>(Token.CONDITION_OPERATOR, Token.ConditionOperator.EQUAL);
break;
case "!=":
token = new Token<>(Token.CONDITION_OPERATOR, Token.ConditionOperator.NOT_EQUAL);
break;
case ">":
token = new Token<>(Token.CONDITION_OPERATOR, Token.ConditionOperator.GREATER);
break;
case "<":
token = new Token<>(Token.CONDITION_OPERATOR, Token.ConditionOperator.LESS);
break;
case ">=":
token = new Token<>(Token.CONDITION_OPERATOR, Token.ConditionOperator.GREATER_OR_EQUAL);
break;
case "<=":
token = new Token<>(Token.CONDITION_OPERATOR, Token.ConditionOperator.LESS_OR_EQUAL);
break;
// Boolean
default:
token = new Token<>(Token.VALUE, stringToken);
}
return token;
}
public List<Token<?>> createNode(Iterable<Token<?>> tokens) {
final Iterator<Token<?>> tokenIterator = tokens.iterator();
final Counter counter = new Counter();
final List<Token<?>> resolvedTokens = resolveNode(tokenIterator, counter).getValue();
if (counter.get() > 0) {
throw new RuntimeException("Start unit '(' without closing it");
} else if (counter.get() < 0) {
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()) {
final Token<?> token = tokens.next();
if (token.getType() == Token.END_UNIT) {
counter.decrement();
break;
} else if (token.getType() == Token.BEGIN_UNIT) {
nodeTokens.add(resolveNode(tokens, counter.increment()));
continue;
}
nodeTokens.add(token);
}
if (nodeTokens.isEmpty()) {
// TODO Create a custom exception
throw new RuntimeException("Empty unit '( )'");
}
if (nodeTokens.size() == 1) {
final Token<?> token = nodeTokens.get(0);
if (token.getType() == Token.NODE) {
return (Token<List<Token<?>>>) token;
}
}
return new Token<>(Token.NODE, nodeTokens);
}
}

View File

@ -1,16 +1,19 @@
package de.epiceric.shopchest.config.hologram.parser;
import java.util.List;
public class Token<T> {
public final static TokenType<String> STRING = new TokenType<>("String");
public final static TokenType<Double> DOUBLE = new TokenType<>("Double");
public final static TokenType<String> BOOLEAN = new TokenType<>("Boolean");
public final static TokenType<String> VALUE = new TokenType<>("Value");
public final static TokenType<Void> BEGIN_UNIT = new TokenType<>("Begin unit");
public final static TokenType<Void> END_UNIT = new TokenType<>("End unit");
public final static TokenType<Void> REVERSE = new TokenType<>("Reverse");
public final static TokenType<ConditionOperator> CONDITION_OPERATOR = new TokenType<>("Condition operator");
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");
private final TokenType<T> type;
private final T value;