Skip to content

Commit

Permalink
Rewrite variable parsing to use element names
Browse files Browse the repository at this point in the history
Signed-off-by: Pablo Herrera <[email protected]>
  • Loading branch information
Pablete1234 committed Aug 23, 2023
1 parent 34036ff commit f77da9f
Show file tree
Hide file tree
Showing 14 changed files with 171 additions and 224 deletions.
2 changes: 1 addition & 1 deletion core/src/main/java/tc/oc/pgm/action/ActionParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ public MessageAction parseChatMessage(Element el, Class<?> scope) throws Invalid
public SoundAction parseSoundAction(Element el, Class<?> scope) throws InvalidXMLException {
SoundType soundType =
XMLUtils.parseEnum(
Node.fromAttr(el, "preset"), SoundType.class, "preset", SoundType.CUSTOM);
Node.fromAttr(el, "preset"), SoundType.class, SoundType.CUSTOM);
Node resourceNode = Node.fromAttr(el, "key");
String resource = resourceNode == null ? soundType.getResource() : resourceNode.getValue();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@ public boolean respondsTo(Class<? extends Query> queryType) {

@Override
public boolean isDynamic() {
// Variables' setValue will always invalidate the filterable directly, no events required
return true;
return variable.isDynamic();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import tc.oc.pgm.util.xml.Node;
import tc.oc.pgm.util.xml.XMLUtils;
import tc.oc.pgm.variables.VariableDefinition;
import tc.oc.pgm.variables.VariableType;
import tc.oc.pgm.variables.VariablesModule;

public class FeatureFilterParser extends FilterParser {
Expand Down Expand Up @@ -100,9 +99,6 @@ public Filter parseNot(Element el) throws InvalidXMLException {
if (varMatch.matches()) {
VariableDefinition<?> variable =
features.resolve(node, varMatch.group(1), VariableDefinition.class);
if (!variable.getVariableType().equals(VariableType.DUMMY)) {
throw new InvalidXMLException("Variable filters only support dummy variables!", node);
}
Range<Double> range = XMLUtils.parseNumericRange(node, varMatch.group(2), Double.class);
return new VariableFilter(variable, range);
}
Expand Down
4 changes: 0 additions & 4 deletions core/src/main/java/tc/oc/pgm/filters/parse/FilterParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@
import tc.oc.pgm.util.xml.Node;
import tc.oc.pgm.util.xml.XMLUtils;
import tc.oc.pgm.variables.VariableDefinition;
import tc.oc.pgm.variables.VariableType;

public abstract class FilterParser implements XMLParser<Filter, FilterDefinition> {

Expand Down Expand Up @@ -660,9 +659,6 @@ public PlayerCountFilter parsePlayerCountFilter(Element el) throws InvalidXMLExc
public Filter parseVariableFilter(Element el) throws InvalidXMLException {
VariableDefinition<?> varDef =
features.resolve(Node.fromRequiredAttr(el, "var"), VariableDefinition.class);
if (!varDef.getVariableType().equals(VariableType.DUMMY)) {
throw new InvalidXMLException("Variable filters only support dummy variables!", el);
}
Range<Double> range = XMLUtils.parseNumericRange(new Node(el), Double.class);

if (varDef.getScope() == Party.class)
Expand Down
42 changes: 15 additions & 27 deletions core/src/main/java/tc/oc/pgm/variables/VariableDefinition.java
Original file line number Diff line number Diff line change
@@ -1,53 +1,41 @@
package tc.oc.pgm.variables;

import java.util.function.Function;
import tc.oc.pgm.api.match.Match;
import tc.oc.pgm.features.SelfIdentifyingFeatureDefinition;
import tc.oc.pgm.filters.Filterable;

public class VariableDefinition<T extends Filterable<?>> extends SelfIdentifyingFeatureDefinition {

private final Class<T> scope;
private final double def;
private final VariableType variableType;

public VariableDefinition(String id, Class<T> scope, double def, VariableType type) {
private final boolean isDynamic;
private final Function<VariableDefinition<T>, Variable<T>> builder;

public VariableDefinition(
String id,
Class<T> scope,
boolean isDynamic,
Function<VariableDefinition<T>, Variable<T>> builder) {
super(id);
this.scope = scope;
this.def = def;
this.variableType = type;
this.isDynamic = isDynamic;
this.builder = builder;
}

public Class<T> getScope() {
return scope;
}

public double getDefault() {
return def;
}

public Variable<?> buildInstance() {
return getVariableType().buildInstance(this);
public boolean isDynamic() {
return isDynamic;
}

public VariableType getVariableType() {
return variableType;
public Variable<T> buildInstance() {
return builder.apply(this);
}

@SuppressWarnings("unchecked")
public Variable<T> getVariable(Match match) {
return (Variable<T>) match.getFeatureContext().get(this.getId());
}

public static class Context<T extends Filterable<?>, C> extends VariableDefinition<T> {
private final C context;

public Context(String id, Class<T> scope, double def, VariableType type, C context) {
super(id, scope, def, type);
this.context = context;
}

public C getContext() {
return context;
}
}
}
92 changes: 92 additions & 0 deletions core/src/main/java/tc/oc/pgm/variables/VariableParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package tc.oc.pgm.variables;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.regex.Pattern;
import org.jdom2.Element;
import tc.oc.pgm.api.feature.FeatureReference;
import tc.oc.pgm.api.filter.Filterables;
import tc.oc.pgm.api.map.factory.MapFactory;
import tc.oc.pgm.api.match.Match;
import tc.oc.pgm.api.party.Party;
import tc.oc.pgm.api.player.MatchPlayer;
import tc.oc.pgm.filters.Filterable;
import tc.oc.pgm.teams.TeamFactory;
import tc.oc.pgm.util.MethodParser;
import tc.oc.pgm.util.MethodParsers;
import tc.oc.pgm.util.xml.InvalidXMLException;
import tc.oc.pgm.util.xml.Node;
import tc.oc.pgm.util.xml.XMLUtils;
import tc.oc.pgm.variables.types.BlitzVariable;
import tc.oc.pgm.variables.types.DummyVariable;
import tc.oc.pgm.variables.types.ScoreVariable;
import tc.oc.pgm.variables.types.TeamVariableAdapter;

public class VariableParser {
// The limitation is due to them being used in exp4j formulas for.
public static final Pattern VARIABLE_ID = Pattern.compile("[A-Za-z_]\\w*");

private final MapFactory factory;
private final Map<String, Method> methodParsers;

public VariableParser(MapFactory factory) {
this.factory = factory;
this.methodParsers = MethodParsers.getMethodParsersForClass(getClass());
}

public VariableDefinition<?> parse(Element el) throws InvalidXMLException {
String id = Node.fromRequiredAttr(el, "id").getValue();
if (!VARIABLE_ID.matcher(id).matches())
throw new InvalidXMLException(
"Variable IDs must start with a letter or underscore and can only include letters, digits or underscores.",
el);

Method parser = methodParsers.get(el.getName().toLowerCase());
if (parser != null) {
try {
return (VariableDefinition<?>) parser.invoke(this, el, id);
} catch (Exception e) {
throw InvalidXMLException.coerce(e, new Node(el));
}
} else {
throw new InvalidXMLException("Unknown variable type: " + el.getName(), el);
}
}

@MethodParser("variable")
public VariableDefinition<?> parseDummy(Element el, String id) throws InvalidXMLException {
Class<? extends Filterable<?>> scope = Filterables.parse(Node.fromRequiredAttr(el, "scope"));
double def = XMLUtils.parseNumber(Node.fromAttr(el, "default"), Double.class, 0d);
return new VariableDefinition<>(id, scope, true, vd -> new DummyVariable<>(vd, def));
}

@MethodParser("lives")
public VariableDefinition<MatchPlayer> parseBlitzLives(Element el, String id)
throws InvalidXMLException {
return new VariableDefinition<>(id, MatchPlayer.class, false, BlitzVariable::new);
}

@MethodParser("score")
public VariableDefinition<Party> parseScore(Element el, String id) throws InvalidXMLException {
return new VariableDefinition<>(id, Party.class, false, ScoreVariable::new);
}

@MethodParser("with-team")
public VariableDefinition<Match> parseTeamAdapter(Element el, String id)
throws InvalidXMLException {
@SuppressWarnings("unchecked")
VariableDefinition<Party> var =
factory.getFeatures().resolve(Node.fromRequiredAttr(el, "var"), VariableDefinition.class);
if (var.getScope() != Party.class) {
throw new InvalidXMLException(
"Team scope is required for with-team variable, got " + var.getScope().getSimpleName(),
el);
}

FeatureReference<TeamFactory> team =
factory.getFeatures().createReference(Node.fromRequiredAttr(el, "team"), TeamFactory.class);

return new VariableDefinition<>(
id, Match.class, var.isDynamic(), vd -> new TeamVariableAdapter(vd, var, team));
}
}
81 changes: 0 additions & 81 deletions core/src/main/java/tc/oc/pgm/variables/VariableType.java

This file was deleted.

35 changes: 4 additions & 31 deletions core/src/main/java/tc/oc/pgm/variables/VariablesModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import tc.oc.pgm.score.ScoreMatchModule;
import tc.oc.pgm.teams.TeamMatchModule;
import tc.oc.pgm.util.xml.InvalidXMLException;
import tc.oc.pgm.util.xml.Node;
import tc.oc.pgm.util.xml.XMLUtils;

public class VariablesModule implements MapModule<VariablesMatchModule> {
Expand Down Expand Up @@ -101,41 +100,15 @@ public VariablesModule parse(MapFactory factory, Logger logger, Document doc)
throws InvalidXMLException {

ImmutableList.Builder<VariableDefinition<?>> variables = ImmutableList.builder();
for (Element variable :
XMLUtils.flattenElements(doc.getRootElement(), "variables", "variable")) {

String id = Node.fromRequiredAttr(variable, "id").getValue();
if (!VARIABLE_ID.matcher(id).matches())
throw new InvalidXMLException(
"Variable IDs must start with a letter or underscore and can only include letters, digits or underscores.",
variable);
VariableType type =
XMLUtils.parseEnum(
Node.fromAttr(variable, "type"), VariableType.class, VariableType.DUMMY);

Class<? extends Filterable<?>> scope = parseScope(variable, type);
double def = XMLUtils.parseNumber(Node.fromAttr(variable, "default"), Double.class, 0d);

if (!type.supports(scope)) {
throw new InvalidXMLException(
"VariableType " + type + " does not support scope: " + scope, variable);
}

VariableDefinition<?> varDef =
new VariableDefinition.Context<>(id, scope, def, type, type.build(factory, variable));
VariableParser parser = new VariableParser(factory);

for (Element variable : XMLUtils.flattenElements(doc.getRootElement(), "variables", null)) {
VariableDefinition<?> varDef = parser.parse(variable);
factory.getFeatures().addFeature(variable, varDef);
variables.add(varDef);
}

return new VariablesModule(variables.build());
}

private Class<? extends Filterable<?>> parseScope(Element variable, VariableType type)
throws InvalidXMLException {
if (type.getDefaultScope() != null && variable.getAttribute("scope") == null) {
return type.getDefaultScope();
}
return Filterables.parse(Node.fromRequiredAttr(variable, "scope"));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,15 @@
import tc.oc.pgm.variables.Variable;
import tc.oc.pgm.variables.VariableDefinition;

public abstract class AbstractVariable<T extends Filterable<?>, D extends VariableDefinition<T>>
implements Variable<T> {
protected final D definition;
public abstract class AbstractVariable<T extends Filterable<?>> implements Variable<T> {
protected final VariableDefinition<T> definition;

public AbstractVariable(D definition) {
public AbstractVariable(VariableDefinition<T> definition) {
this.definition = definition;
}

@Override
public D getDefinition() {
public VariableDefinition<T> getDefinition() {
return definition;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
import tc.oc.pgm.blitz.BlitzMatchModule;
import tc.oc.pgm.variables.VariableDefinition;

public class BlitzVariable extends AbstractVariable<MatchPlayer, VariableDefinition<MatchPlayer>> {
public class BlitzVariable extends AbstractVariable<MatchPlayer> {

private BlitzMatchModule bmm;

public BlitzVariable(VariableDefinition<?> definition) {
super((VariableDefinition<MatchPlayer>) definition);
public BlitzVariable(VariableDefinition<MatchPlayer> definition) {
super(definition);
}

@Override
Expand Down
Loading

0 comments on commit f77da9f

Please sign in to comment.