refactor shorthand nodes

This commit is contained in:
Luck 2016-11-17 20:50:37 +00:00
parent a047695a84
commit 6293634e36
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
2 changed files with 178 additions and 56 deletions

View File

@ -33,11 +33,11 @@ import me.lucko.luckperms.api.MetaUtils;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.constants.Patterns;
import me.lucko.luckperms.common.utils.ShorthandParser;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
/**
* An immutable permission node
@ -150,7 +150,7 @@ public class Node implements me.lucko.luckperms.api.Node {
suffix = Maps.immutableEntry(i, MetaUtils.unescapeCharacters(suffixPart.get(1)));
}
resolvedShorthand = calculateShorthand();
resolvedShorthand = ImmutableList.copyOf(ShorthandParser.parseShorthand(getPermission()));
serializedNode = calculateSerializedNode();
}
@ -413,60 +413,6 @@ public class Node implements me.lucko.luckperms.api.Node {
return serializedNode;
}
private List<String> calculateShorthand() {
if (!Patterns.SHORTHAND_NODE.matcher(getPermission()).find()) {
return ImmutableList.of();
}
if (!getPermission().contains(".")) {
return ImmutableList.of();
}
Iterable<String> parts = Splitter.on('.').split(getPermission());
List<Set<String>> nodeParts = new ArrayList<>();
for (String s : parts) {
if ((!s.startsWith("(") || !s.endsWith(")")) || (!s.contains("|") && !s.contains("-"))) {
nodeParts.add(Collections.singleton(s));
continue;
}
final String bits = s.substring(1, s.length() - 1);
if (s.contains("|")) {
nodeParts.add(new HashSet<>(Splitter.on('|').splitToList(bits)));
} else {
List<String> range = Splitter.on('-').limit(2).splitToList(bits);
if (isChar(range.get(0), range.get(1))) {
nodeParts.add(getCharRange(range.get(0).charAt(0), range.get(1).charAt(0)));
} else if (isInt(range.get(0), range.get(1))) {
nodeParts.add(IntStream.rangeClosed(Integer.parseInt(range.get(0)), Integer.parseInt(range.get(1))).boxed()
.map(i -> "" + i)
.collect(Collectors.toSet())
);
} else {
// Fallback
nodeParts.add(Collections.singleton(s));
}
}
}
Set<String> nodes = new HashSet<>();
for (Set<String> set : nodeParts) {
final Set<String> newNodes = new HashSet<>();
if (nodes.isEmpty()) {
newNodes.addAll(set);
} else {
nodes.forEach(str -> newNodes.addAll(set.stream()
.map(add -> str + "." + add)
.collect(Collectors.toList()))
);
}
nodes = newNodes;
}
return ImmutableList.copyOf(nodes);
}
private String calculateSerializedNode() {
StringBuilder builder = new StringBuilder();

View File

@ -0,0 +1,176 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.common.utils;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class ShorthandParser {
private static final List<Function<String, List<String>>> PARSERS = ImmutableList.<Function<String, List<String>>>builder()
.add(new ListParser())
.add(new CharacterRangeParser())
.add(new NumericRangeParser())
.build();
public static Set<String> parseShorthand(String s) {
Set<String> results = new HashSet<>();
results.add(s);
while (true) {
Set<String> working = new HashSet<>();
int beforeSize = results.size();
for (String str : results) {
Set<String> ret = captureResults(str);
if (ret != null) {
working.addAll(ret);
} else {
working.add(str);
}
}
if (working.size() != beforeSize) {
results = working;
continue;
}
break;
}
results.remove(s);
return results;
}
private static Set<String> captureResults(String s) {
s = s.replace('(', '{').replace(')', '}');
int openingIndex = s.indexOf('{');
if (openingIndex == -1) {
return null;
}
int closingIndex = s.indexOf('}');
if (closingIndex < openingIndex) {
return null;
}
String before = s.substring(0, openingIndex);
String after = s.substring(closingIndex + 1);
String between = s.substring(openingIndex + 1, closingIndex);
Set<String> results = new HashSet<>();
for (Function<String, List<String>> parser : PARSERS) {
List<String> res = parser.apply(between);
if (res != null) {
for (String r : res) {
results.add(before + r + after);
}
}
}
return results;
}
private static class ListParser implements Function<String, List<String>> {
@Override
public List<String> apply(String s) {
if (s.contains("|")) {
s = s.replace('|', ',');
}
if (!s.contains(",")) {
return null;
}
return Splitter.on(',').splitToList(s);
}
}
private static class NumericRangeParser implements Function<String, List<String>> {
@Override
public List<String> apply(String s) {
int index = s.indexOf("-");
if (index == -1) {
return null;
}
String before = s.substring(0, index);
String after = s.substring(index + 1);
if (isInt(before) && isInt(after)) {
return IntStream.rangeClosed(Integer.parseInt(before), Integer.parseInt(after)).boxed().map(i -> "" + i).collect(Collectors.toList());
}
return null;
}
private static boolean isInt(String a) {
try {
Integer.parseInt(a);
return true;
} catch (NumberFormatException e) {
return false;
}
}
}
private static class CharacterRangeParser implements Function<String, List<String>> {
@Override
public List<String> apply(String s) {
int index = s.indexOf("-");
if (index == -1) {
return null;
}
String before = s.substring(0, s.indexOf("-"));
String after = s.substring(s.indexOf("-") + 1);
if (before.length() == 1 && after.length() == 1) {
return getCharRange(before.charAt(0), after.charAt(0));
}
return null;
}
private static List<String> getCharRange(char a, char b) {
List<String> s = new ArrayList<>();
for (char c = a; c <= b; c++) {
s.add(Character.toString(c));
}
return s;
}
}
}