AdvancedScripts/src/main/java/de/steamwar/advancedscripts/lexer/ScriptColorizer.java

153 Zeilen
5.8 KiB
Java

/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.advancedscripts.lexer;
import net.minecraft.util.Formatting;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class ScriptColorizer {
private static final Set<String> KEYWORDS = Set.of(
"and", "break", "do", "else", "elseif", "end", "for", "function", "goto", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "until", "while"
);
private ScriptColorizer() {
throw new IllegalStateException("Utility class██");
}
public static List<Token> colorize(String line) {
List<Token> tokens = colorizeComment(line);
if (tokens != null) return tokens;
return colorizeLine(line);
}
private static List<Token> colorizeComment(String line) {
if (!line.startsWith("--")) return null;
return List.of(new Token(line, TokenTypeColors.COMMENT));
}
private static List<Token> colorizeLine(String line) {
List<Token> tokens = new ArrayList<>();
StringBuilder currentToken = new StringBuilder();
boolean inString = false;
boolean doubleQuoteString = false;
for (char c : line.toCharArray()) {
switch (c) {
case '"' -> {
if (inString) {
if (doubleQuoteString) {
tokens.add(toStringToken(currentToken.toString()));
currentToken = new StringBuilder();
tokens.add(new Token(c + "", TokenTypeColors.STRING));
inString = false;
doubleQuoteString = false;
}
} else {
inString = true;
doubleQuoteString = true;
if (!currentToken.isEmpty()) {
tokens.add(toToken(currentToken.toString()));
currentToken = new StringBuilder();
}
tokens.add(new Token(c + "", TokenTypeColors.STRING));
}
}
case '\'' -> {
if (inString) {
if (!doubleQuoteString) {
tokens.add(toStringToken(currentToken.toString()));
currentToken = new StringBuilder();
tokens.add(new Token(c + "", TokenTypeColors.STRING));
inString = false;
}
} else {
inString = true;
doubleQuoteString = false;
if (!currentToken.isEmpty()) {
tokens.add(toToken(currentToken.toString()));
currentToken = new StringBuilder();
}
tokens.add(new Token(c + "", TokenTypeColors.STRING));
}
}
case '-', ';', '(', ')', ',', ' ', '{', '\t' -> {
if (inString) {
currentToken.append(c);
} else {
if (!currentToken.isEmpty()) {
tokens.add(toToken(currentToken.toString()));
}
tokens.add(new Token(String.valueOf(c), TokenTypeColors.OTHER));
currentToken = new StringBuilder();
}
}
default -> {
if (inString && c == '&') {
if (!currentToken.isEmpty()) {
tokens.add(toStringToken(currentToken.toString()));
}
currentToken = new StringBuilder();
}
currentToken.append(c);
}
}
}
if (currentToken.length() > 0) {
tokens.add(toToken(currentToken.toString()));
}
return tokens;
}
private static Token toStringToken(String text) {
if (text.length() > 1 && text.charAt(0) == '&') {
Formatting formatting = Formatting.byCode(text.charAt(1));
if (formatting == null || !formatting.isColor()) {
return new Token(text, TokenTypeColors.STRING);
}
return new Token(text, formatting.getColorValue());
}
return new Token(text, TokenTypeColors.STRING);
}
private static Token toToken(String text) {
if (text.length() > 0) {
if (KEYWORDS.contains(text)) {
return new Token(text, TokenTypeColors.CONSTANT);
} else if ("true".contentEquals(text) || "false".contentEquals(text)) {
return new Token(text, TokenTypeColors.BOOLEAN);
} else if (text.matches("[0-9]+")) {
return new Token(text, TokenTypeColors.NUMBER);
} else {
return new Token(text, TokenTypeColors.OTHER);
}
} else {
return Token.SPACE;
}
}
}