From b8fc15a6a8de065536a3d38a76096b4d628e536d Mon Sep 17 00:00:00 2001 From: Flowsqy <47575244+Flowsqy@users.noreply.github.com> Date: Tue, 22 Feb 2022 19:53:57 +0100 Subject: [PATCH] Improve and fix unit detection, add nodes --- .../config/hologram/parser/Counter.java | 29 +++ .../config/hologram/parser/FormatParser.java | 243 ++++++++++-------- .../config/hologram/parser/Token.java | 5 +- 3 files changed, 171 insertions(+), 106 deletions(-) create mode 100644 plugin/src/main/java/de/epiceric/shopchest/config/hologram/parser/Counter.java diff --git a/plugin/src/main/java/de/epiceric/shopchest/config/hologram/parser/Counter.java b/plugin/src/main/java/de/epiceric/shopchest/config/hologram/parser/Counter.java new file mode 100644 index 0000000..ecd870c --- /dev/null +++ b/plugin/src/main/java/de/epiceric/shopchest/config/hologram/parser/Counter.java @@ -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; + } + +} diff --git a/plugin/src/main/java/de/epiceric/shopchest/config/hologram/parser/FormatParser.java b/plugin/src/main/java/de/epiceric/shopchest/config/hologram/parser/FormatParser.java index 3a471a6..1f4864c 100644 --- a/plugin/src/main/java/de/epiceric/shopchest/config/hologram/parser/FormatParser.java +++ b/plugin/src/main/java/de/epiceric/shopchest/config/hologram/parser/FormatParser.java @@ -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> createNode(Iterable> tokens) { + final Iterator> tokenIterator = tokens.iterator(); + final Counter counter = new Counter(); + final List> 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>> resolveNode(Iterator> tokens, Counter counter) { + final List> 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>>) token; + } + } + return new Token<>(Token.NODE, nodeTokens); } } diff --git a/plugin/src/main/java/de/epiceric/shopchest/config/hologram/parser/Token.java b/plugin/src/main/java/de/epiceric/shopchest/config/hologram/parser/Token.java index 410f6b2..ab009bc 100644 --- a/plugin/src/main/java/de/epiceric/shopchest/config/hologram/parser/Token.java +++ b/plugin/src/main/java/de/epiceric/shopchest/config/hologram/parser/Token.java @@ -1,16 +1,19 @@ package de.epiceric.shopchest.config.hologram.parser; +import java.util.List; + public class Token { public final static TokenType STRING = new TokenType<>("String"); public final static TokenType DOUBLE = new TokenType<>("Double"); - public final static TokenType BOOLEAN = new TokenType<>("Boolean"); + public final static TokenType VALUE = new TokenType<>("Value"); public final static TokenType BEGIN_UNIT = new TokenType<>("Begin unit"); public final static TokenType END_UNIT = new TokenType<>("End unit"); public final static TokenType REVERSE = new TokenType<>("Reverse"); public final static TokenType CONDITION_OPERATOR = new TokenType<>("Condition operator"); public final static TokenType LOGIC_OPERATOR = new TokenType<>("Logic operator"); public final static TokenType CALCULATION_OPERATOR = new TokenType<>("Calculation operator"); + public final static TokenType>> NODE = new TokenType<>("Node"); private final TokenType type; private final T value;