diff --git a/src/main/java/com/github/manolo8/darkbot/Bot.java b/src/main/java/com/github/manolo8/darkbot/Bot.java index b8d822b62..1cae194c6 100644 --- a/src/main/java/com/github/manolo8/darkbot/Bot.java +++ b/src/main/java/com/github/manolo8/darkbot/Bot.java @@ -33,6 +33,20 @@ public static void main(String[] args) throws IOException { LogUtils.setupLogOutput(); + setupUI(); + + LibSetup.setupLibraries(); + StartupParams params = new StartupParams(args); + + System.out.println("Starting DarkBot " + Main.VERSION); + //noinspection ThrowableNotThrown + Runtime.getRuntime().addShutdownHook(new Thread(() -> + new Throwable("DarkBot shutdown peacefully!").printStackTrace())); + + SwingUtilities.invokeLater(() -> new Main(params)); + } + + public static void setupUI() { try { UIManager.put("MenuItem.selectionType", "underline"); UIManager.getFont("Label.font"); // Prevents a linux crash @@ -63,16 +77,6 @@ public static void main(String[] args) throws IOException { } catch (UnsupportedLookAndFeelException e) { e.printStackTrace(); } - - LibSetup.setupLibraries(); - StartupParams params = new StartupParams(args); - - System.out.println("Starting DarkBot " + Main.VERSION); - //noinspection ThrowableNotThrown - Runtime.getRuntime().addShutdownHook(new Thread(() -> - new Throwable("DarkBot shutdown peacefully!").printStackTrace())); - - SwingUtilities.invokeLater(() -> new Main(params)); } @SuppressWarnings("removal") diff --git a/src/main/java/com/github/manolo8/darkbot/config/actions/Condition.java b/src/main/java/com/github/manolo8/darkbot/config/actions/Condition.java index f781f4a9f..0d2e1a523 100644 --- a/src/main/java/com/github/manolo8/darkbot/config/actions/Condition.java +++ b/src/main/java/com/github/manolo8/darkbot/config/actions/Condition.java @@ -4,21 +4,18 @@ import eu.darkbot.api.PluginAPI; import org.jetbrains.annotations.NotNull; +@Deprecated public interface Condition extends Value, eu.darkbot.api.config.types.Condition { - @Override - default @NotNull eu.darkbot.api.config.types.Condition.Result get(PluginAPI pluginAPI) { - Result result = get(pluginAPI.requireInstance(Main.class)); - - return eu.darkbot.api.config.types.Condition.Result.values()[result.ordinal()]; - } - /** * @deprecated Use {@link #get(PluginAPI)} instead */ @Deprecated - @NotNull Result get(Main main); + default @NotNull Result get(Main main) { + return Result.values()[get(main.pluginAPI).ordinal()]; + } + @Deprecated enum Result { ALLOW, DENY, ABSTAIN; diff --git a/src/main/java/com/github/manolo8/darkbot/config/actions/LegacyCondition.java b/src/main/java/com/github/manolo8/darkbot/config/actions/LegacyCondition.java new file mode 100644 index 000000000..854e81a9f --- /dev/null +++ b/src/main/java/com/github/manolo8/darkbot/config/actions/LegacyCondition.java @@ -0,0 +1,15 @@ +package com.github.manolo8.darkbot.config.actions; + +/** + * This class exists PURELY to avoid an import mess. + * Condition implementations need to keep implementing darkbot's Condition (interface) + * for backwards-compat with older plugins, but if they implement darkbot's Condition directly, + * Condition.Result is darkbot's condition instead of the API's. To solve this, they will now + * implement LegacyCondition so that ConditionResult is the api's condition. + *
+ * This will be all removed in a future release, when legacy plugins stop using legacy conditions and have + * fully migrated to the API's condition type. + */ +@SuppressWarnings("deprecation") +public interface LegacyCondition extends Condition { +} diff --git a/src/main/java/com/github/manolo8/darkbot/config/actions/Parser.java b/src/main/java/com/github/manolo8/darkbot/config/actions/Parser.java index 30224a758..9c8de277f 100644 --- a/src/main/java/com/github/manolo8/darkbot/config/actions/Parser.java +++ b/src/main/java/com/github/manolo8/darkbot/config/actions/Parser.java @@ -1,5 +1,7 @@ package com.github.manolo8.darkbot.config.actions; +import com.github.manolo8.darkbot.config.actions.tree.ParsingNode; + public interface Parser { - String parse(String str) throws SyntaxException; + void parse(ParsingNode node) throws SyntaxException; } diff --git a/src/main/java/com/github/manolo8/darkbot/config/actions/SyntaxException.java b/src/main/java/com/github/manolo8/darkbot/config/actions/SyntaxException.java index af6a4882b..5ceee56de 100644 --- a/src/main/java/com/github/manolo8/darkbot/config/actions/SyntaxException.java +++ b/src/main/java/com/github/manolo8/darkbot/config/actions/SyntaxException.java @@ -1,26 +1,73 @@ package com.github.manolo8.darkbot.config.actions; import com.github.manolo8.darkbot.config.actions.parser.Values; +import com.github.manolo8.darkbot.gui.utils.highlight.Locatable; +import lombok.Getter; +import lombok.experimental.Delegate; import org.jetbrains.annotations.NotNull; +import javax.swing.text.Position; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Objects; -public class SyntaxException extends Exception { +public class SyntaxException extends RuntimeException implements Locatable { private static final String[] EMPTY = new String[]{}; - private final String at; + @Delegate + private final Locatable loc; private final String[] chars; private final List> metadatas; + @Getter private boolean singleMeta = false; + public SyntaxException(String message, Locatable loc, String... chars) { + super(message); + this.loc = loc; + this.chars = chars == null ? EMPTY : chars; + this.metadatas = Collections.emptyList(); + } + + public SyntaxException(String message, Locatable loc, Values.Meta meta, String... chars) { + this(message, loc, meta == null ? null : Collections.singletonList(meta), chars); + singleMeta = true; + } + + public SyntaxException(String message, Locatable loc, List> metas, String... chars) { + super(message); + this.loc = loc; + this.chars = chars == null ? EMPTY : chars; + this.metadatas = metas == null ? Collections.emptyList() : metas; + } + + public > SyntaxException(String message, Locatable loc, Class metadatas) { + this(message, loc, (List>) null, Arrays.stream(metadatas.getEnumConstants()) + .map(Objects::toString).toArray(String[]::new)); + } + public SyntaxException(String message, String at) { this(message, at, (List>) null, (String[]) null); } + public SyntaxException(String message, int atIdx, String... chars) { + super(message); + this.loc = new Locatable() { + @Override + public Position getStart() { + return () -> atIdx; + } + + @Override + public Position getEnd() { + return null; + } + }; + this.chars = chars == null ? EMPTY : chars; + this.metadatas = Collections.emptyList(); + } + public > SyntaxException(String message, String at, Class metadatas) { this(message, at, (List>) null, Arrays.stream(metadatas.getEnumConstants()) .map(Objects::toString).toArray(String[]::new)); @@ -33,13 +80,13 @@ public SyntaxException(String message, String at, Values.Meta meta, String... public SyntaxException(String message, String at, List> metas, String... chars) { super(message); - this.at = at == null ? "" : at; + this.loc = null; this.chars = chars == null ? EMPTY : chars; this.metadatas = metas == null ? Collections.emptyList() : metas; } - public String getAt() { - return at; + public int getAt() { + return loc.getStart().getOffset(); } public @NotNull String[] getExpected() { @@ -50,8 +97,4 @@ public String getAt() { return metadatas; } - public boolean isSingleMeta() { - return singleMeta; - } - } diff --git a/src/main/java/com/github/manolo8/darkbot/config/actions/Value.java b/src/main/java/com/github/manolo8/darkbot/config/actions/Value.java index 2c9ea1106..a09e4f53b 100644 --- a/src/main/java/com/github/manolo8/darkbot/config/actions/Value.java +++ b/src/main/java/com/github/manolo8/darkbot/config/actions/Value.java @@ -1,20 +1,26 @@ package com.github.manolo8.darkbot.config.actions; import com.github.manolo8.darkbot.Main; +import eu.darkbot.api.PluginAPI; +import eu.darkbot.api.config.types.Condition; import org.jetbrains.annotations.Nullable; public interface Value { - @Nullable R get(Main main); + @Nullable R get(Main api); static T get(Value val, Main main) { if (val == null) return null; return val.get(main); } - static boolean allows(Value val, Main main) { - Condition.Result res = get(val, main); + static boolean allows(Value val, PluginAPI api) { + Condition.Result res = get(val, api); return res != null && res.allows(); } + static T get(Value val, PluginAPI api) { + return get(val, api.requireInstance(Main.class)); + } + } diff --git a/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/AbstractCondition.java b/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/AbstractCondition.java index 36063a3af..d96eb69ea 100644 --- a/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/AbstractCondition.java +++ b/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/AbstractCondition.java @@ -1,41 +1,43 @@ package com.github.manolo8.darkbot.config.actions.conditions; -import com.github.manolo8.darkbot.Main; -import com.github.manolo8.darkbot.config.actions.Condition; +import com.github.manolo8.darkbot.config.actions.LegacyCondition; import com.github.manolo8.darkbot.config.actions.Parser; import com.github.manolo8.darkbot.config.actions.SyntaxException; import com.github.manolo8.darkbot.config.actions.ValueData; -import com.github.manolo8.darkbot.config.actions.parser.ParseResult; -import com.github.manolo8.darkbot.config.actions.parser.ParseUtil; import com.github.manolo8.darkbot.config.actions.parser.ValueParser; -import com.github.manolo8.darkbot.config.actions.parser.Values; +import com.github.manolo8.darkbot.config.actions.tree.ParsingNode; +import eu.darkbot.api.PluginAPI; +import eu.darkbot.api.config.types.Condition; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; -public abstract class AbstractCondition implements Condition, Parser { +import static eu.darkbot.api.config.types.Condition.Result.ABSTAIN; +import static eu.darkbot.api.config.types.Condition.Result.ALLOW; +import static eu.darkbot.api.config.types.Condition.Result.DENY; + +public abstract class AbstractCondition implements LegacyCondition, Parser { - public int min, max; public List children; public AbstractCondition() { children = new ArrayList<>(); } - public Result getValue(Main main, int min, int max) { + public Condition.Result getValue(PluginAPI api, int min, int max) { int[] states = new int[]{0, 0, 0}; for (int i = 0; i < children.size(); i++) { - states[children.get(i).get(main).ordinal()]++; + states[children.get(i).get(api).ordinal()]++; if ((states[1] + states[2] > children.size() - min && states[0] + states[1] > 0) /* Can't reach min anymore */ || states[0] > max /* Allow bigger than max */) { - return Condition.Result.DENY; + return DENY; } if (states[0] >= min && states[0] + (children.size() - 1 - i) >= max) { /* Won't go bigger than max */ - return Condition.Result.ALLOW; + return ALLOW; } } - return states[0] >= min ? Condition.Result.ALLOW : Condition.Result.ABSTAIN; + return states[0] >= min ? ALLOW : ABSTAIN; } protected String name() { @@ -48,20 +50,10 @@ public String toString() { } @Override - public String parse(String str) throws SyntaxException { - boolean hasNext; - do { - ParseResult pr = ValueParser.parse(str, Result.class); - if (!(pr.value instanceof Condition)) - throw new SyntaxException("Error: Expected boolean condition", str, Values.getMeta(getClass())); - - children.add((Condition) pr.value); - str = pr.leftover.trim(); - - hasNext = !str.isEmpty() && str.charAt(0) == ','; - str = ParseUtil.separate(str, getClass(), ",", ")"); - } while (hasNext); - return str; + public void parse(ParsingNode node) throws SyntaxException { + for (ParsingNode child : node.getChildren()) { + children.add(ValueParser.parseCondition(child)); + } } } diff --git a/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/AfterCondition.java b/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/AfterCondition.java index 286934b80..365958f5c 100644 --- a/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/AfterCondition.java +++ b/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/AfterCondition.java @@ -1,36 +1,31 @@ package com.github.manolo8.darkbot.config.actions.conditions; -import com.github.manolo8.darkbot.Main; -import com.github.manolo8.darkbot.config.actions.Condition; +import com.github.manolo8.darkbot.config.actions.LegacyCondition; import com.github.manolo8.darkbot.config.actions.Parser; import com.github.manolo8.darkbot.config.actions.SyntaxException; -import com.github.manolo8.darkbot.config.actions.Value; import com.github.manolo8.darkbot.config.actions.ValueData; -import com.github.manolo8.darkbot.config.actions.parser.ParseResult; -import com.github.manolo8.darkbot.config.actions.parser.ParseUtil; import com.github.manolo8.darkbot.config.actions.parser.ValueParser; +import com.github.manolo8.darkbot.config.actions.tree.ParsingNode; import com.github.manolo8.darkbot.config.actions.values.NumberConstant; -import com.github.manolo8.darkbot.core.entities.Ship; +import eu.darkbot.api.PluginAPI; +import eu.darkbot.api.config.types.Condition; import org.jetbrains.annotations.NotNull; -import java.util.Locale; - @ValueData(name = "after", description = "Returns true if inner condition is true after the specified time in seconds", example = "after(7.5, condition)") -public class AfterCondition implements Condition, Parser { +public class AfterCondition implements LegacyCondition, Parser { public long time; - public Value condition; + public Condition condition; private transient Long allowTime = null; @Override - public @NotNull Condition.Result get(Main main) { - Result res = Value.get(condition, main); - if (res == null) return Result.ABSTAIN; + public @NotNull Condition.Result get(PluginAPI api) { + Condition.Result res = condition.get(api); allowTime = res.allows() ? allowTime != null ? allowTime : System.currentTimeMillis() + time : null; - return Result.fromBoolean(allowTime != null && System.currentTimeMillis() > allowTime); + return Condition.Result.fromBoolean(allowTime != null && System.currentTimeMillis() > allowTime); } @@ -40,16 +35,10 @@ public String toString() { } @Override - public String parse(String str) throws SyntaxException { - String[] params = str.split(" *, *", 2); - - time = (long) (NumberConstant.parseNumber(params[0], str, getClass()).doubleValue() * 1000); - - str = ParseUtil.separate(params, getClass(), ","); - - ParseResult pr = ValueParser.parse(str, Result.class); - condition = pr.value; + public void parse(ParsingNode node) throws SyntaxException { + node.requireParamSize(2, getClass()); - return ParseUtil.separate(pr.leftover.trim(), getClass(), ")"); + time = (long) (NumberConstant.parseNumber(node.getParam(0), getClass()).doubleValue() * 1000); + condition = ValueParser.parseCondition(node.getParam(1)); } } diff --git a/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/AllCondition.java b/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/AllCondition.java index 697405033..ab2474949 100644 --- a/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/AllCondition.java +++ b/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/AllCondition.java @@ -1,15 +1,16 @@ package com.github.manolo8.darkbot.config.actions.conditions; -import com.github.manolo8.darkbot.Main; import com.github.manolo8.darkbot.config.actions.ValueData; +import eu.darkbot.api.PluginAPI; +import eu.darkbot.api.config.types.Condition; import org.jetbrains.annotations.NotNull; @ValueData(name = "all", description = "Returns true if all child conditions return true", example = "all(a, b)") public class AllCondition extends AbstractCondition { @Override - public @NotNull Result get(Main main) { - return super.getValue(main, children.size(), children.size()); + public @NotNull Condition.Result get(PluginAPI api) { + return super.getValue(api, children.size(), children.size()); } } diff --git a/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/AnyCondition.java b/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/AnyCondition.java index 1104a126b..cf38bb66d 100644 --- a/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/AnyCondition.java +++ b/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/AnyCondition.java @@ -1,15 +1,16 @@ package com.github.manolo8.darkbot.config.actions.conditions; -import com.github.manolo8.darkbot.Main; import com.github.manolo8.darkbot.config.actions.ValueData; +import eu.darkbot.api.PluginAPI; +import eu.darkbot.api.config.types.Condition; import org.jetbrains.annotations.NotNull; @ValueData(name = "any", description = "Returns true if any child conditions return true", example = "any(a, b)") public class AnyCondition extends AbstractCondition { @Override - public @NotNull Result get(Main main) { - return super.getValue(main, 1, children.size()); + public @NotNull Condition.Result get(PluginAPI api) { + return super.getValue(api, 1, children.size()); } } diff --git a/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/EqualCondition.java b/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/EqualCondition.java index de1f90ae2..c67c475e6 100644 --- a/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/EqualCondition.java +++ b/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/EqualCondition.java @@ -1,36 +1,37 @@ package com.github.manolo8.darkbot.config.actions.conditions; -import com.github.manolo8.darkbot.Main; -import com.github.manolo8.darkbot.config.actions.Condition; +import com.github.manolo8.darkbot.config.actions.LegacyCondition; import com.github.manolo8.darkbot.config.actions.Parser; import com.github.manolo8.darkbot.config.actions.SyntaxException; import com.github.manolo8.darkbot.config.actions.Value; import com.github.manolo8.darkbot.config.actions.ValueData; import com.github.manolo8.darkbot.config.actions.parser.ParseResult; -import com.github.manolo8.darkbot.config.actions.parser.ParseUtil; import com.github.manolo8.darkbot.config.actions.parser.ValueParser; +import com.github.manolo8.darkbot.config.actions.tree.ParsingNode; import com.github.manolo8.darkbot.utils.ReflectionUtils; +import eu.darkbot.api.PluginAPI; +import eu.darkbot.api.config.types.Condition; import org.jetbrains.annotations.NotNull; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; @ValueData(name = "equal", description = "Returns true if both parameters are the same", example = "equal(a, b)") -public class EqualCondition implements Condition, Parser { +public class EqualCondition implements LegacyCondition, Parser { private Boolean isComparable; private Value a, b; @Override - public @NotNull Result get(Main main) { - Object objA = Value.get(a, main), objB = Value.get(b, main); - if (objA == null || objB == null) return Result.ABSTAIN; + public @NotNull Condition.Result get(PluginAPI api) { + Object objA = Value.get(a, api), objB = Value.get(b, api); + if (objA == null || objB == null) return Condition.Result.ABSTAIN; if (isComparable == null) isComparable = isComparable(objA, objB); if (isComparable) //noinspection unchecked - return Result.fromBoolean(((Comparable) objA).compareTo(objB) == 0); - return Result.fromBoolean(objA.equals(objB)); + return Condition.Result.fromBoolean(((Comparable) objA).compareTo(objB) == 0); + return Condition.Result.fromBoolean(objA.equals(objB)); } @Override @@ -50,18 +51,14 @@ private boolean isComparable(Object a, Object b) { } @Override - public String parse(String str) throws SyntaxException { - ParseResult prA = ValueParser.parse(str); - a = prA.value; - - str = ParseUtil.separate(prA.leftover.trim(), getClass(), ","); + public void parse(ParsingNode node) throws SyntaxException { + node.requireParamSize(2, getClass()); - ParseResult prB = ValueParser.parse(str, prA.type); - b = prB.value; + ParseResult prA = ValueParser.parseGeneric(node.getParam(0)); + a = prA.value; + b = ValueParser.parse(node.getParam(1), prA.type); isComparable = null; - - return ParseUtil.separate(prB.leftover.trim(), getClass(), ")"); } } diff --git a/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/HasEffectCondition.java b/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/HasEffectCondition.java index 60ab01de1..412b13267 100644 --- a/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/HasEffectCondition.java +++ b/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/HasEffectCondition.java @@ -1,31 +1,31 @@ package com.github.manolo8.darkbot.config.actions.conditions; -import com.github.manolo8.darkbot.Main; -import com.github.manolo8.darkbot.config.actions.Condition; +import com.github.manolo8.darkbot.config.actions.LegacyCondition; import com.github.manolo8.darkbot.config.actions.Parser; import com.github.manolo8.darkbot.config.actions.SyntaxException; import com.github.manolo8.darkbot.config.actions.Value; import com.github.manolo8.darkbot.config.actions.ValueData; -import com.github.manolo8.darkbot.config.actions.parser.ParseResult; -import com.github.manolo8.darkbot.config.actions.parser.ParseUtil; import com.github.manolo8.darkbot.config.actions.parser.ValueParser; +import com.github.manolo8.darkbot.config.actions.tree.ParsingNode; import com.github.manolo8.darkbot.core.entities.Ship; +import eu.darkbot.api.PluginAPI; +import eu.darkbot.api.config.types.Condition; import org.jetbrains.annotations.NotNull; import java.util.Locale; @ValueData(name = "has-effect", description = "Checks if a ship has an effect", example = "has-effect(effect, ship)") -public class HasEffectCondition implements Condition, Parser { +public class HasEffectCondition implements LegacyCondition, Parser { public Effect effect; public Value ship; @Override - public @NotNull Condition.Result get(Main main) { + public @NotNull Condition.Result get(PluginAPI api) { Ship sh; - if ((effect == null) || (sh = Value.get(ship, main)) == null) return Result.ABSTAIN; + if ((effect == null) || (sh = Value.get(ship, api)) == null) return Condition.Result.ABSTAIN; - return Result.fromBoolean(main.effectManager.hasEffect(sh, effect.id)); + return Condition.Result.fromBoolean(sh.hasEffect(effect.id)); } public enum Effect { @@ -73,11 +73,12 @@ public String toString() { return name().toLowerCase(Locale.ROOT).replace("_", "-"); } - public static Effect of(String operation) { + public static Effect of(ParsingNode node) { + String effect = node.getString(); for (Effect ef : Effect.values()) { - if (ef.toString().equals(operation)) return ef; + if (ef.toString().equals(effect)) return ef; } - return null; + throw new SyntaxException("Unknown effect: '" + effect + "'", node, Effect.class); } } @@ -88,17 +89,10 @@ public String toString() { } @Override - public String parse(String str) throws SyntaxException { - String[] params = str.split(" *, *", 2); - effect = Effect.of(params[0].trim()); - if (effect == null) - throw new SyntaxException("Unknown effect: '" + params[0] + "'", str, Effect.class); + public void parse(ParsingNode node) throws SyntaxException { + node.requireParamSize(2, getClass()); - str = ParseUtil.separate(params, getClass(), ","); - - ParseResult pr = ValueParser.parse(str, Ship.class); - ship = pr.value; - - return ParseUtil.separate(pr.leftover.trim(), getClass(), ")"); + effect = Effect.of(node.getParam(0)); + ship = ValueParser.parse(node.getParam(1), Ship.class); } } diff --git a/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/HasFormationCondition.java b/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/HasFormationCondition.java index 774817d5f..b7f496fff 100644 --- a/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/HasFormationCondition.java +++ b/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/HasFormationCondition.java @@ -1,31 +1,31 @@ package com.github.manolo8.darkbot.config.actions.conditions; -import com.github.manolo8.darkbot.Main; -import com.github.manolo8.darkbot.config.actions.Condition; +import com.github.manolo8.darkbot.config.actions.LegacyCondition; import com.github.manolo8.darkbot.config.actions.Parser; import com.github.manolo8.darkbot.config.actions.SyntaxException; import com.github.manolo8.darkbot.config.actions.Value; import com.github.manolo8.darkbot.config.actions.ValueData; -import com.github.manolo8.darkbot.config.actions.parser.ParseResult; -import com.github.manolo8.darkbot.config.actions.parser.ParseUtil; import com.github.manolo8.darkbot.config.actions.parser.ValueParser; +import com.github.manolo8.darkbot.config.actions.tree.ParsingNode; import com.github.manolo8.darkbot.core.entities.Ship; +import eu.darkbot.api.PluginAPI; +import eu.darkbot.api.config.types.Condition; import org.jetbrains.annotations.NotNull; import java.util.Locale; @ValueData(name = "has-formation", description = "Checks if a ship has a formation", example = "has-formation(formation, ship)") -public class HasFormationCondition implements Condition, Parser { +public class HasFormationCondition implements LegacyCondition, Parser { public Formation formation; public Value ship; @Override - public @NotNull Condition.Result get(Main main) { + public @NotNull Condition.Result get(PluginAPI main) { Ship sh; - if ((formation == null) || (sh = Value.get(ship, main)) == null) return Result.ABSTAIN; + if ((formation == null) || (sh = Value.get(ship, main)) == null) return Condition.Result.ABSTAIN; - return Result.fromBoolean(sh.formationId == formation.id); + return Condition.Result.fromBoolean(sh.formationId == formation.id); } public enum Formation { @@ -59,11 +59,12 @@ public String toString() { return name().toLowerCase(Locale.ROOT).replace("_", "-"); } - public static Formation of(String operation) { + public static Formation of(ParsingNode node) { + String formation = node.getString(); for (Formation f : Formation.values()) { - if (f.toString().equals(operation)) return f; + if (f.toString().equals(formation)) return f; } - return null; + throw new SyntaxException("Unknown formation: '" + formation + "'", node, Formation.class); } } @@ -73,17 +74,10 @@ public String toString() { } @Override - public String parse(String str) throws SyntaxException { - String[] params = str.split(" *, *", 2); - formation = Formation.of(params[0].trim()); - if (formation == null) - throw new SyntaxException("Unknown formation: '" + params[0] + "'", str, Formation.class); + public void parse(ParsingNode node) throws SyntaxException { + node.requireParamSize(2, getClass()); - str = ParseUtil.separate(params, getClass(), ","); - - ParseResult pr = ValueParser.parse(str, Ship.class); - ship = pr.value; - - return ParseUtil.separate(pr.leftover.trim(), getClass(), ")"); + formation = Formation.of(node.getParam(0)); + ship = ValueParser.parse(node.getParam(1), Ship.class); } } diff --git a/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/NoneCondition.java b/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/NoneCondition.java index abedcd0b1..b967bcd0f 100644 --- a/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/NoneCondition.java +++ b/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/NoneCondition.java @@ -1,7 +1,8 @@ package com.github.manolo8.darkbot.config.actions.conditions; -import com.github.manolo8.darkbot.Main; import com.github.manolo8.darkbot.config.actions.ValueData; +import eu.darkbot.api.PluginAPI; +import eu.darkbot.api.config.types.Condition; import org.jetbrains.annotations.NotNull; @ValueData(name = "none", description = "Returns true if no child conditions return true", example = "none(a, b)") @@ -10,8 +11,8 @@ public class NoneCondition extends AbstractCondition { public NoneCondition() {} @Override - public @NotNull Result get(Main main) { - return super.getValue(main, 0, 0); + public @NotNull Condition.Result get(PluginAPI api) { + return super.getValue(api, 0, 0); } } diff --git a/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/NumericalCondition.java b/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/NumericalCondition.java index 3dceae8ef..922c9864d 100644 --- a/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/NumericalCondition.java +++ b/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/NumericalCondition.java @@ -1,27 +1,27 @@ package com.github.manolo8.darkbot.config.actions.conditions; -import com.github.manolo8.darkbot.Main; -import com.github.manolo8.darkbot.config.actions.Condition; +import com.github.manolo8.darkbot.config.actions.LegacyCondition; import com.github.manolo8.darkbot.config.actions.Parser; import com.github.manolo8.darkbot.config.actions.SyntaxException; import com.github.manolo8.darkbot.config.actions.Value; import com.github.manolo8.darkbot.config.actions.ValueData; -import com.github.manolo8.darkbot.config.actions.parser.ParseResult; -import com.github.manolo8.darkbot.config.actions.parser.ParseUtil; import com.github.manolo8.darkbot.config.actions.parser.ValueParser; +import com.github.manolo8.darkbot.config.actions.tree.ParsingNode; +import eu.darkbot.api.PluginAPI; +import eu.darkbot.api.config.types.Condition; import org.jetbrains.annotations.NotNull; import java.util.function.BiPredicate; @ValueData(name = "if", description = "Compares two numbers", example = "if(a > b)") -public class NumericalCondition implements Condition, Parser { +public class NumericalCondition implements LegacyCondition, Parser { public Value a; public Operation operation; public Value b; @Override - public @NotNull Condition.Result get(Main main) { + public @NotNull Condition.Result get(PluginAPI main) { Number numA, numB; if ((numA = Value.get(a, main)) == null || (numB = Value.get(b, main)) == null || operation == null) return Condition.Result.ABSTAIN; @@ -49,11 +49,12 @@ public String toString() { return display; } - public static Operation of(String operation) { + public static Operation of(ParsingNode node) { + String operation = node.getString(); for (Operation op : Operation.values()) { if (op.toString().equals(operation)) return op; } - return null; + throw new SyntaxException("Unknown operation '" + operation + "'", node, Operation.class); } } @@ -64,20 +65,11 @@ public String toString() { } @Override - public String parse(String str) throws SyntaxException { - ParseResult prA = ValueParser.parse(str, Number.class); - a = prA.value; - str = prA.leftover.trim(); + public void parse(ParsingNode node) throws SyntaxException { + node.requireParamSize(3, getClass()); - int chars = Math.min(str.length(), str.length() > 1 && str.charAt(1) == '=' ? 2 : 1); - - String op = str.substring(0, chars); - operation = Operation.of(op); - if (operation == null) - throw new SyntaxException("Unknown operation '" + op + "'", str, Operation.class); - - ParseResult prB = ValueParser.parse(str.substring(chars), Number.class); - b = prB.value; - return ParseUtil.separate(prB.leftover.trim(), getClass(), ")"); + a = ValueParser.parse(node.getParam(0), Number.class); + operation = Operation.of(node.getParam(1)); + a = ValueParser.parse(node.getParam(2), Number.class); } } diff --git a/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/OneCondition.java b/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/OneCondition.java index 842f124d2..49f86ebdb 100644 --- a/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/OneCondition.java +++ b/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/OneCondition.java @@ -1,15 +1,16 @@ package com.github.manolo8.darkbot.config.actions.conditions; -import com.github.manolo8.darkbot.Main; import com.github.manolo8.darkbot.config.actions.ValueData; +import eu.darkbot.api.PluginAPI; +import eu.darkbot.api.config.types.Condition; import org.jetbrains.annotations.NotNull; @ValueData(name = "one", description = "Returns true if exactly one child condition return true", example = "one(a, b)") public class OneCondition extends AbstractCondition { @Override - public @NotNull Result get(Main main) { - return super.getValue(main, 1, 1); + public @NotNull Condition.Result get(PluginAPI api) { + return super.getValue(api, 1, 1); } } diff --git a/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/TargetTypeCondition.java b/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/TargetTypeCondition.java index 49528e977..3a3723311 100644 --- a/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/TargetTypeCondition.java +++ b/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/TargetTypeCondition.java @@ -1,15 +1,15 @@ package com.github.manolo8.darkbot.config.actions.conditions; -import com.github.manolo8.darkbot.Main; -import com.github.manolo8.darkbot.config.actions.Condition; +import com.github.manolo8.darkbot.config.actions.LegacyCondition; import com.github.manolo8.darkbot.config.actions.Parser; import com.github.manolo8.darkbot.config.actions.SyntaxException; import com.github.manolo8.darkbot.config.actions.Value; import com.github.manolo8.darkbot.config.actions.ValueData; -import com.github.manolo8.darkbot.config.actions.parser.ParseResult; -import com.github.manolo8.darkbot.config.actions.parser.ParseUtil; import com.github.manolo8.darkbot.config.actions.parser.ValueParser; +import com.github.manolo8.darkbot.config.actions.tree.ParsingNode; import com.github.manolo8.darkbot.core.entities.Ship; +import eu.darkbot.api.PluginAPI; +import eu.darkbot.api.config.types.Condition; import eu.darkbot.api.game.entities.Npc; import eu.darkbot.api.game.other.EntityInfo.Diplomacy; import org.jetbrains.annotations.NotNull; @@ -17,17 +17,17 @@ import java.util.Locale; @ValueData(name = "has-relation", description = "Checks the target type", example = "has-relation(npc, target())") -public class TargetTypeCondition implements Condition, Parser { +public class TargetTypeCondition implements LegacyCondition, Parser { private TargetType type; private Value ship; @Override - public @NotNull Condition.Result get(Main main) { + public @NotNull Condition.Result get(PluginAPI api) { if (type == null) { - return Result.ABSTAIN; + return Condition.Result.ABSTAIN; } - return Result.fromBoolean(matches(Value.get(ship, main))); + return Condition.Result.fromBoolean(matches(Value.get(ship, api))); } private boolean matches(Ship target) { @@ -61,11 +61,12 @@ public String toString() { return name().toLowerCase(Locale.ROOT).replace("_", "-"); } - public static TargetType of(String targetType) { + public static TargetType of(ParsingNode node) { + String targetType = node.getString(); for (TargetType tt : TargetType.values()) { if (tt.toString().equals(targetType)) return tt; } - return null; + throw new SyntaxException("Unknown type: '" + targetType + "'", node, TargetType.class); } } @@ -75,20 +76,9 @@ public String toString() { } @Override - public String parse(String str) throws SyntaxException { - String[] params = str.split(" *, *", 2); - - type = TargetType.of(params[0].trim()); - - if (type == null) { - throw new SyntaxException("Unknown has-relation: '" + params[0] + "'", str, TargetType.class); - } - - str = ParseUtil.separate(params, getClass(), ","); - - ParseResult pr = ValueParser.parse(str, Ship.class); - ship = pr.value; - - return ParseUtil.separate(pr.leftover.trim(), getClass(), ")"); + public void parse(ParsingNode node) throws SyntaxException { + node.requireParamSize(2, getClass()); + type = TargetType.of(node.getParam(0)); + ship = ValueParser.parse(node.getParam(1), Ship.class); } } \ No newline at end of file diff --git a/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/UntilCondition.java b/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/UntilCondition.java index 4b73d884f..a06de0f78 100644 --- a/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/UntilCondition.java +++ b/src/main/java/com/github/manolo8/darkbot/config/actions/conditions/UntilCondition.java @@ -1,26 +1,26 @@ package com.github.manolo8.darkbot.config.actions.conditions; -import com.github.manolo8.darkbot.Main; -import com.github.manolo8.darkbot.config.actions.Condition; +import com.github.manolo8.darkbot.config.actions.LegacyCondition; import com.github.manolo8.darkbot.config.actions.Value; import com.github.manolo8.darkbot.config.actions.ValueData; +import eu.darkbot.api.PluginAPI; +import eu.darkbot.api.config.types.Condition; import org.jetbrains.annotations.NotNull; @ValueData(name = "until", description = "Returns true if the first matches until the second one turns true", example = "until(a, b)") -public class UntilCondition implements Condition { +public class UntilCondition implements LegacyCondition { - public Value from, until; + public Value from, until; private transient boolean current = false; @Override - public @NotNull Condition.Result get(Main main) { - if (Value.allows(current ? until : from, main)) current = !current; + public @NotNull Condition.Result get(PluginAPI api) { + if (Value.allows(current ? until : from, api)) current = !current; - return Result.fromBoolean(current); + return Condition.Result.fromBoolean(current); } - @Override public String toString() { return "until(" + from + ", " + until + ")"; diff --git a/src/main/java/com/github/manolo8/darkbot/config/actions/parser/ParseResult.java b/src/main/java/com/github/manolo8/darkbot/config/actions/parser/ParseResult.java index 63a649f4a..8a8bcbd8f 100644 --- a/src/main/java/com/github/manolo8/darkbot/config/actions/parser/ParseResult.java +++ b/src/main/java/com/github/manolo8/darkbot/config/actions/parser/ParseResult.java @@ -5,11 +5,10 @@ public class ParseResult { public final Value value; public final Class type; - public final String leftover; - public ParseResult(Value value, Class type, String leftover) { + public ParseResult(Value value, Class type) { this.value = value; this.type = type; - this.leftover = leftover; } + } \ No newline at end of file diff --git a/src/main/java/com/github/manolo8/darkbot/config/actions/parser/ParseUtil.java b/src/main/java/com/github/manolo8/darkbot/config/actions/parser/ParseUtil.java deleted file mode 100644 index c9719aeb9..000000000 --- a/src/main/java/com/github/manolo8/darkbot/config/actions/parser/ParseUtil.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.github.manolo8.darkbot.config.actions.parser; - -import com.github.manolo8.darkbot.config.actions.SyntaxException; -import com.github.manolo8.darkbot.config.actions.Value; - -import java.util.Arrays; - -public class ParseUtil { - - public static String separate(String[] parts, Class> val, String... expected) throws SyntaxException { - return separate(parts, Values.getMeta(val), expected); - } - - public static String separate(String[] parts, Values.Meta meta, String... expected) throws SyntaxException { - if (parts.length != 2) - throw new SyntaxException("Missing separator in '" + meta.getName() + "'", "", meta, expected); - return parts[1].trim(); - } - - public static String separate(String str, Class> val, String... expected) throws SyntaxException{ - return separate(str, Values.getMeta(val), expected); - } - - public static String separate(String str, Values.Meta meta, String... expected) throws SyntaxException{ - String match = Arrays.stream(expected).filter(str::startsWith).findFirst().orElse(null); - if (str.isEmpty() || match == null) - throw new SyntaxException("Missing separator in '" + meta.getName() + "'", str, meta, expected); - return str.substring(match.length()).trim(); - } - -} diff --git a/src/main/java/com/github/manolo8/darkbot/config/actions/parser/ValueParser.java b/src/main/java/com/github/manolo8/darkbot/config/actions/parser/ValueParser.java index 21cb22f98..35bb2560a 100644 --- a/src/main/java/com/github/manolo8/darkbot/config/actions/parser/ValueParser.java +++ b/src/main/java/com/github/manolo8/darkbot/config/actions/parser/ValueParser.java @@ -1,52 +1,67 @@ package com.github.manolo8.darkbot.config.actions.parser; -import com.github.manolo8.darkbot.config.actions.Condition; import com.github.manolo8.darkbot.config.actions.Parser; import com.github.manolo8.darkbot.config.actions.SyntaxException; import com.github.manolo8.darkbot.config.actions.Value; +import com.github.manolo8.darkbot.config.actions.tree.DocumentReader; +import com.github.manolo8.darkbot.config.actions.tree.ParsingNode; +import com.github.manolo8.darkbot.gui.utils.highlight.Locatable; import com.github.manolo8.darkbot.utils.ReflectionUtils; +import eu.darkbot.api.config.types.Condition; + +import javax.swing.text.Document; public class ValueParser { - public static Condition parseCondition(String str) throws SyntaxException { - ParseResult result = parse(str, Condition.Result.class); - if (!result.leftover.trim().isEmpty()) - throw new SyntaxException("Unused characters after end", result.leftover); - return (Condition) result.value; + public static Condition parseCondition(String str) { + return parseCondition(new DocumentReader(str)); } - public static Value parseValue(String str) throws SyntaxException { - ParseResult result = parse(str); - if (!result.leftover.trim().isEmpty()) - throw new SyntaxException("Unused characters after end", result.leftover); - return result.value; + public static Condition parseCondition(Document document) { + return parseCondition(new DocumentReader(document)); } - public static ParseResult parse(String str) throws SyntaxException { - return parse(str, Object.class); + public static Condition parseCondition(DocumentReader reader) throws SyntaxException { + reader.reset(); + ParsingNode root = new ParsingNode(reader); + return parseCondition(root); } - public static ParseResult parse(String str, Class type) throws SyntaxException { - String[] parts = str.trim().split(" *\\( *", 2); + public static Condition parseCondition(ParsingNode node) { + // Technically it's a Value that is implemented by api Condition. + return (Condition) parseImpl(node, com.github.manolo8.darkbot.config.actions.Condition.Result.class).value; + } - Values.Meta vm = Values.getMeta(parts[0].trim(), str, type); + public static Value parse(ParsingNode node, Class type) { + return parseImpl(node, type).value; + } + + public static ParseResult parseGeneric(ParsingNode node) { + return parseImpl(node, Object.class); + } - str = ParseUtil.separate(parts, vm, "("); + private static ParseResult parseImpl(ParsingNode node, Class type) { + Values.Meta vm = Values.getMeta(node, type); Value val = ReflectionUtils.createInstance(vm.clazz); - if (val instanceof Parser) str = ((Parser) val).parse(str); + if (val instanceof Parser) ((Parser) val).parse(node); else { - for (Values.Param param : vm.params) { - ParseResult pr = parse(str, param.type); - ReflectionUtils.set(param.field, val, pr.value); - - str = ParseUtil.separate(pr.leftover.trim(), vm, param == vm.params[vm.params.length - 1] ? ")" : ","); + if (vm.params.length > node.getChildCount()) { + int p = node.getEnd().getOffset() - 1; + throw new SyntaxException("Missing separator in '" + node.getFunction() + "'", Locatable.of(p, p), vm, ","); + } else if (vm.params.length < node.getChildCount()) { + throw new SyntaxException("Too many parameters, expected " + vm.params.length, Locatable.of( + node.getChildAt(vm.params.length).getStart().getOffset(), + node.getChildAt(node.getChildCount() - 1).getEnd().getOffset()), vm); } - if (vm.params.length == 0) str = ParseUtil.separate(str, vm, ")"); + int idx = 0; + for (Values.Param param : vm.params) { + ReflectionUtils.set(param.field, val, parseImpl(node.getParam(idx++), param.type).value); + } } - return new ParseResult<>(val, vm.type, str); + return new ParseResult<>(val, vm.type); } } diff --git a/src/main/java/com/github/manolo8/darkbot/config/actions/parser/Values.java b/src/main/java/com/github/manolo8/darkbot/config/actions/parser/Values.java index b811fd802..e6ff68599 100644 --- a/src/main/java/com/github/manolo8/darkbot/config/actions/parser/Values.java +++ b/src/main/java/com/github/manolo8/darkbot/config/actions/parser/Values.java @@ -15,6 +15,7 @@ import com.github.manolo8.darkbot.config.actions.conditions.OneCondition; import com.github.manolo8.darkbot.config.actions.conditions.TargetTypeCondition; import com.github.manolo8.darkbot.config.actions.conditions.UntilCondition; +import com.github.manolo8.darkbot.config.actions.tree.ParsingNode; import com.github.manolo8.darkbot.config.actions.values.BooleanConstant; import com.github.manolo8.darkbot.config.actions.values.DistanceValue; import com.github.manolo8.darkbot.config.actions.values.HealthTypeValue; @@ -96,18 +97,18 @@ public static > Meta getMeta(Class type) throws SyntaxE throw new SyntaxException("Error: failed to find value meta for " + type.getSimpleName(), null); } - public static Meta getMeta(String name, String ex, Class type) throws SyntaxException { + public static Meta getMeta(ParsingNode node, Class type) throws SyntaxException { //noinspection unchecked - Meta meta = (Meta) VALUES.get(name); + Meta meta = (Meta) VALUES.get(node.getFunction()); List> params = VALUES.values().stream() .filter(v -> type.isAssignableFrom(v.type)) .collect(Collectors.toList()); if (meta == null) - throw new SyntaxException("Unknown value type '" + name + "'", ex, params); + throw new SyntaxException("Unknown value type '" + node.getFunction() + "'", node, params); if (!type.isAssignableFrom(meta.type)) - throw new SyntaxException("Invalid type, expected '" + type.getSimpleName() + "'", ex, params); + throw new SyntaxException("Invalid type, expected '" + type.getSimpleName() + "'", node, params); return meta; } diff --git a/src/main/java/com/github/manolo8/darkbot/config/actions/tree/ConditionEditorPanel.java b/src/main/java/com/github/manolo8/darkbot/config/actions/tree/ConditionEditorPanel.java new file mode 100644 index 000000000..8d08341a5 --- /dev/null +++ b/src/main/java/com/github/manolo8/darkbot/config/actions/tree/ConditionEditorPanel.java @@ -0,0 +1,104 @@ +package com.github.manolo8.darkbot.config.actions.tree; + +import com.github.manolo8.darkbot.Bot; +import com.github.manolo8.darkbot.config.actions.SyntaxException; +import com.github.manolo8.darkbot.gui.tree.editors.ConditionEditor; +import com.github.manolo8.darkbot.gui.utils.GeneralDocumentListener; +import com.github.manolo8.darkbot.gui.utils.UIUtils; +import com.github.manolo8.darkbot.gui.utils.highlight.BorderHighlightPainter; +import com.github.manolo8.darkbot.gui.utils.highlight.HighlightHandler; +import com.github.manolo8.darkbot.gui.utils.highlight.Locatable; +import eu.darkbot.util.Popups; + +import javax.swing.*; +import javax.swing.text.DefaultHighlighter; +import javax.swing.tree.TreeModel; +import javax.swing.tree.TreeNode; +import javax.swing.tree.TreePath; +import java.awt.*; + +/** + * In-testing new condition editor + */ +public class ConditionEditorPanel extends JPanel { + + private final ConditionEditor textArea = new ConditionEditor(); + private final DocumentReader reader = new DocumentReader(textArea.getDocument()); + + private final ParsingNode root = new ParsingNode(); + private final ParseTreeModel treeModel = new ParseTreeModel(root); + private final JTree tree = new ConditionTree(treeModel); + + private final HighlightHandler locationHighlight = + new HighlightHandler(textArea, new BorderHighlightPainter(UIUtils.BLUE_HIGHLIGHT)); + private final HighlightHandler errorHighlight = + new HighlightHandler(textArea, new DefaultHighlighter.DefaultHighlightPainter(UIUtils.RED_HIGHLIGHT)); + + + public ConditionEditorPanel(String initialText) { + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + setPreferredSize(new Dimension(800, 500)); + + add(new JScrollPane(textArea)); + add(new JScrollPane(tree)); + + textArea.getDocument().addDocumentListener((GeneralDocumentListener) e -> { + try { + reader.reset(); + root.parse(reader); + errorHighlight.remove(); + } catch (SyntaxException ex) { + errorHighlight.setHighlight(ex.getAt(), textArea.getDocument().getLength()); + } + + treeModel.updateListeners(); + for (int i = 0; i < tree.getRowCount(); i++) { + TreeNode node = (TreeNode) tree.getPathForRow(i).getLastPathComponent(); + if (node instanceof ParsingNode && !((ParsingNode) node).isSmall()) tree.expandRow(i); + } + }); + + // Sync tree selection to editor highlight + tree.addTreeSelectionListener(event -> { + TreeNode node = (TreeNode) event.getPath().getLastPathComponent(); + if (node instanceof Locatable) locationHighlight.setHighlight((Locatable) node); + }); + + // Sync editor caret to tree highlight + textArea.addCaretListener(e -> { + int a = e.getDot(), b = e.getMark(); + ParsingNode node = root.getAtPosition(Math.min(a, b), Math.max(a, b)); + if (node != null) tree.setSelectionPath(new TreePath(treeModel.getPathToRoot(node))); + }); + + textArea.setText(initialText); + textArea.init(); + } + + private static class ConditionTree extends JTree { + public ConditionTree(TreeModel model) { + super(model); + } + + + // Simple custom node rendering + @Override + public String convertValueToText(Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { + return value instanceof ParsingNode ? ((ParsingNode) value).getPrettyPrinted() : value.toString(); + } + + } + + // Condition editor testing + public static void main(String[] args) { + Bot.setupUI(); + UIManager.put("Tree.paintLines", true); + Popups.of("Condition editor", new ConditionEditorPanel( + "any(\n" + + " if(hp-type(hp-percent, health(hero())) <= percent(35)), \n" + + " all(none(has-effect(leech, hero())), if(hp-type(shield-percent, health(hero())) <= percent(10))))")) + .border(BorderFactory.createEmptyBorder()) + .showAsync(); + } + +} diff --git a/src/main/java/com/github/manolo8/darkbot/config/actions/tree/DocumentReader.java b/src/main/java/com/github/manolo8/darkbot/config/actions/tree/DocumentReader.java new file mode 100644 index 000000000..120d63e63 --- /dev/null +++ b/src/main/java/com/github/manolo8/darkbot/config/actions/tree/DocumentReader.java @@ -0,0 +1,124 @@ +package com.github.manolo8.darkbot.config.actions.tree; + +import com.github.manolo8.darkbot.config.actions.SyntaxException; +import lombok.SneakyThrows; + +import javax.swing.text.Document; +import javax.swing.text.GapContent; +import javax.swing.text.PlainDocument; +import javax.swing.text.Position; +import javax.swing.text.Segment; +import java.util.regex.Pattern; + +public class DocumentReader { + // "\\\\" compiles to string literal \\, which is one regex escaped \ + private static final Pattern ESCAPES_REGEX = Pattern.compile("\\\\(.)"); + + private final Segment BUFFER = new Segment(); + + private final Document document; + private int nextIdx; + + @SneakyThrows + public DocumentReader(String string) { + this.document = new PlainDocument(new GapContent(string.length())); + this.document.insertString(0, string, null); + } + + public DocumentReader(Document document) { + this.document = document; + } + + /** + * Reads a text (arbitrary string) as defined below: + * Any character is eligible, except for '(' ',' ')' and any whitespace char. + * You may use a quoted string "string" for any char except " being eligible. + * Either of them may be escaped by using \, and \ can be escaped by \\. + * @return The next word read in full. + */ + public String readText() { + boolean quoted = pollIf('"'); + + for (int i = nextIdx; i < document.getLength(); i++) { + char ch = charAt(i); + if (ch == '\\') { + // Skip the next char, it's been escaped + i++; + } else if (quoted ? ch == '"' : ch == '(' || ch == ',' || ch == ')' || ch == ' ') { + if (nextIdx == i) + throw new SyntaxException("Invalid text, expected at least one char", nextIdx); + + String result = ESCAPES_REGEX.matcher(substring(nextIdx, i)).replaceAll("$1"); + nextIdx = i + (quoted ? 1 : 0); + return result; + } + } + + if (quoted) { + throw new SyntaxException("Unfinished quoted string", nextIdx, "\""); + } + + String remaining = substring(nextIdx, document.getLength()); + nextIdx = document.getLength(); + return remaining; + } + + public void done() { + if (nextIdx < document.getLength()) + throw new SyntaxException("Unused characters after end", nextIdx); + } + + public char peekNext() { + if (nextIdx >= document.getLength()) return '\04'; // EOF + return charAt(nextIdx); + } + + @SneakyThrows + public Position getPosition() { + return document.createPosition(nextIdx); + } + + public void skipWhitespace() { + for (int i = nextIdx; i < document.getLength(); i++) { + if (!Character.isWhitespace(charAt(i))) { + nextIdx = i; + break; + } + } + } + + /** + * Peek at the next char ignoring whitespace, if it's {@param ch}, poll it and return true + * @param ch the char to maybe expect next + * @return true if the next char is ch, and it was skipped, false otherwise + */ + public boolean pollIf(char ch) { + for (int i = nextIdx; i < document.getLength(); i++) { + char currChar = charAt(i); + if (currChar == ch) { + nextIdx = i + 1; + return true; + } else if (!Character.isWhitespace(currChar)) { + return false; + } + } + return false; + } + + public void reset() { + this.nextIdx = 0; + } + + @SneakyThrows + public String substring(int start, int end) { + return document.getText(start, end - start); + } + + @SneakyThrows + public char charAt(int pos) { + document.getText(pos, 1, BUFFER); + return BUFFER.charAt(0); + } + + +} diff --git a/src/main/java/com/github/manolo8/darkbot/config/actions/tree/ParseTreeModel.java b/src/main/java/com/github/manolo8/darkbot/config/actions/tree/ParseTreeModel.java new file mode 100644 index 000000000..2d4e4b5b3 --- /dev/null +++ b/src/main/java/com/github/manolo8/darkbot/config/actions/tree/ParseTreeModel.java @@ -0,0 +1,22 @@ +package com.github.manolo8.darkbot.config.actions.tree; + +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreePath; + +public class ParseTreeModel extends DefaultTreeModel { + + public ParseTreeModel(ParsingNode root) { + super(root); + } + + public void updateListeners() { + fireTreeStructureChanged(this, null, null, null); + } + + @Override + public void valueForPathChanged(TreePath path, Object newValue) { + + } + +} + diff --git a/src/main/java/com/github/manolo8/darkbot/config/actions/tree/ParsingNode.java b/src/main/java/com/github/manolo8/darkbot/config/actions/tree/ParsingNode.java new file mode 100644 index 000000000..320333072 --- /dev/null +++ b/src/main/java/com/github/manolo8/darkbot/config/actions/tree/ParsingNode.java @@ -0,0 +1,168 @@ +package com.github.manolo8.darkbot.config.actions.tree; + +import com.github.manolo8.darkbot.config.actions.SyntaxException; +import com.github.manolo8.darkbot.config.actions.Value; +import com.github.manolo8.darkbot.config.actions.parser.Values; +import com.github.manolo8.darkbot.gui.utils.highlight.Locatable; +import lombok.AccessLevel; +import lombok.Getter; + +import javax.swing.text.Position; +import javax.swing.tree.TreeNode; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import java.util.stream.Collectors; + +@Getter +public class ParsingNode implements TreeNode, Locatable { + private final ParsingNode parent; + + private Position start; + private String function = ""; + private List children; + private Position end; + + @Getter(AccessLevel.NONE) + private int totalChildren; + + public ParsingNode() { + parent = null; + } + + public ParsingNode(DocumentReader reader) { + this(); + reader.reset(); + parse(reader); + reader.done(); + } + + private ParsingNode(ParsingNode parent) { + this.parent = parent; + } + + public void parse(DocumentReader str) { + str.skipWhitespace(); + start = str.getPosition(); + this.function = str.readText(); + + // Standalone leaf node! a raw value with no (), eg the VAL in: + // string(VAL) or has-effect(VAL, hero()) + if (!str.pollIf('(')) { + this.children = null; + this.totalChildren = 0; + } else { + this.function = this.function.trim(); + this.children = new ArrayList<>(); + + // 0 parameter function + if (!str.pollIf(')')) { + while (true) { + ParsingNode node = new ParsingNode(this); + node.parse(str); + children.add(node); + + if (str.pollIf(')')) break; + if (str.pollIf(',') || str.pollIf(' ')) continue; + + throw new SyntaxException( + "Expected one of ')' or ',' but found '" + str.peekNext() + "'", + str.getPosition().getOffset()); + } + } + totalChildren = children.stream().mapToInt(ch -> ch.totalChildren + 1).sum(); + } + end = str.getPosition(); + } + + public boolean isSmall() { + return totalChildren <= 7; + } + + public String getPrettyPrinted() { + return function + " " + ( + children == null ? "" : + children.isEmpty() ? "()" : + !isSmall() ? "(...)" : + children.stream().map(ParsingNode::toString) + .collect(Collectors.joining(", ", "( ", " )"))); + } + + public String toString() { + return escape(function) + (children == null ? "" : + children.stream().map(ParsingNode::toString) + .collect(Collectors.joining(", ", "(", ")"))); + } + + public static String escape(String val) { + for (char c : val.toCharArray()) { + if (c == '(' || c == ',' || c == ')' || c == ' ') + return '"' + val.replaceAll("([\\\\\"])", "\\$1") + '"'; + } + return val; + } + + public ParsingNode getAtPosition(int min, int max) { + if (children == null) return this; + + for (ParsingNode param : children) { + if (param.getStart().getOffset() <= min && param.getEnd().getOffset() >= max) { + return param.getAtPosition(min, max); + } + } + return this; + } + + public void requireParamSize(int size, Class> type) { + if ((children == null ? -1 : children.size()) != size) { + String curr = children == null ? "none" : String.valueOf(getChildCount()); + String expected = size == -1 ? "none" : String.valueOf(size); + throw new SyntaxException("Invalid parameter count, found " + curr + " but expected " + expected, this, Values.getMeta(type)); + } + } + + public ParsingNode getParam(int idx) { + if (idx >= getChildCount()) throw new SyntaxException("Missing parameter #" + (idx + 1), this); + return children.get(idx); + } + + public String getParamStr(int idx) { + return getParam(idx).getString(); + } + + public String getString() { + if (children != null) throw new SyntaxException("Expected no parameters", this); + return function; + } + + @Override + public ParsingNode getChildAt(int childIndex) { + return children.get(childIndex); + } + + @Override + public int getChildCount() { + return children == null ? 0 : children.size(); + } + + @Override + public int getIndex(TreeNode node) { + return children.indexOf((ParsingNode) node); + } + + @Override + public boolean getAllowsChildren() { + return true; + } + + @Override + public boolean isLeaf() { + return children == null; + } + + @Override + public Enumeration children() { + return Collections.enumeration(children); + } +} diff --git a/src/main/java/com/github/manolo8/darkbot/config/actions/values/BooleanConstant.java b/src/main/java/com/github/manolo8/darkbot/config/actions/values/BooleanConstant.java index 0cba866d7..83c942368 100644 --- a/src/main/java/com/github/manolo8/darkbot/config/actions/values/BooleanConstant.java +++ b/src/main/java/com/github/manolo8/darkbot/config/actions/values/BooleanConstant.java @@ -1,30 +1,29 @@ package com.github.manolo8.darkbot.config.actions.values; -import com.github.manolo8.darkbot.Main; -import com.github.manolo8.darkbot.config.actions.Condition; +import com.github.manolo8.darkbot.config.actions.LegacyCondition; import com.github.manolo8.darkbot.config.actions.Parser; import com.github.manolo8.darkbot.config.actions.SyntaxException; import com.github.manolo8.darkbot.config.actions.ValueData; -import com.github.manolo8.darkbot.config.actions.parser.ParseUtil; import com.github.manolo8.darkbot.config.actions.parser.Values; +import com.github.manolo8.darkbot.config.actions.tree.ParsingNode; +import eu.darkbot.api.PluginAPI; +import eu.darkbot.api.config.types.Condition; import org.jetbrains.annotations.NotNull; @ValueData(name = "boolean", description = "Boolean constant", example = "boolean(true)") -public class BooleanConstant implements Condition, Parser { +public class BooleanConstant implements LegacyCondition, Parser { private Boolean value; @Override - public @NotNull Result get(Main main) { - return Result.fromBoolean(value); + public @NotNull Condition.Result get(PluginAPI api) { + return Condition.Result.fromBoolean(value); } @Override - public String parse(String str) throws SyntaxException { - String[] params = str.split("\\)", 2); - - value = parse(params[0].trim(), str); - return ParseUtil.separate(params, getClass(), ")"); + public void parse(ParsingNode node) throws SyntaxException { + node.requireParamSize(1, getClass()); + value = parseBoolean(node.getParam(0)); } @Override @@ -32,13 +31,13 @@ public String toString() { return "boolean(" + value + ")"; } - private Boolean parse(String bool, String ex) throws SyntaxException { - switch (bool) { + private Boolean parseBoolean(ParsingNode node) throws SyntaxException { + switch (node.getString()) { case "null": return null; case "true": return true; case "false": return false; default: - throw new SyntaxException("Failed to parse boolean '" + bool + "'", ex, Values.getMeta(getClass()), "true", "false"); + throw new SyntaxException("Failed to parse boolean '" + node.getString() + "'", node, Values.getMeta(getClass()), "true", "false"); } } diff --git a/src/main/java/com/github/manolo8/darkbot/config/actions/values/HealthTypeValue.java b/src/main/java/com/github/manolo8/darkbot/config/actions/values/HealthTypeValue.java index 72577ac94..bcf761cf0 100644 --- a/src/main/java/com/github/manolo8/darkbot/config/actions/values/HealthTypeValue.java +++ b/src/main/java/com/github/manolo8/darkbot/config/actions/values/HealthTypeValue.java @@ -5,10 +5,8 @@ import com.github.manolo8.darkbot.config.actions.SyntaxException; import com.github.manolo8.darkbot.config.actions.Value; import com.github.manolo8.darkbot.config.actions.ValueData; -import com.github.manolo8.darkbot.config.actions.parser.ParseResult; -import com.github.manolo8.darkbot.config.actions.parser.ParseUtil; import com.github.manolo8.darkbot.config.actions.parser.ValueParser; -import com.github.manolo8.darkbot.config.actions.parser.Values; +import com.github.manolo8.darkbot.config.actions.tree.ParsingNode; import com.github.manolo8.darkbot.core.objects.itf.HealthHolder; import java.util.Locale; @@ -46,11 +44,12 @@ public String toString() { return name().toLowerCase(Locale.ROOT).replace("_", "-"); } - public static HealthType of(String healthType) { + public static HealthType of(ParsingNode node) { + String healthType = node.getString(); for (HealthType ht : HealthType.values()) { if (ht.toString().equals(healthType)) return ht; } - return null; + throw new SyntaxException("Unknown hp-type: '" + healthType + "'", node, HealthType.class); } } @@ -60,17 +59,9 @@ public String toString() { } @Override - public String parse(String str) throws SyntaxException { - String[] params = str.split(" *, *", 2); - healthType = HealthType.of(params[0].trim()); - if (healthType == null) - throw new SyntaxException("Unknown hp-type: '" + params[0] + "'", str, HealthType.class); - - str = ParseUtil.separate(params, getClass(), ","); - - ParseResult pr = ValueParser.parse(str, HealthHolder.class); - health = pr.value; - - return ParseUtil.separate(pr.leftover.trim(), getClass(), ")"); + public void parse(ParsingNode node) throws SyntaxException { + node.requireParamSize(2, getClass()); + healthType = HealthType.of(node.getParam(0)); + health = ValueParser.parse(node.getParam(1), HealthHolder.class); } } diff --git a/src/main/java/com/github/manolo8/darkbot/config/actions/values/LocationConstant.java b/src/main/java/com/github/manolo8/darkbot/config/actions/values/LocationConstant.java index ed2e1d565..006186bc0 100644 --- a/src/main/java/com/github/manolo8/darkbot/config/actions/values/LocationConstant.java +++ b/src/main/java/com/github/manolo8/darkbot/config/actions/values/LocationConstant.java @@ -5,8 +5,7 @@ import com.github.manolo8.darkbot.config.actions.SyntaxException; import com.github.manolo8.darkbot.config.actions.Value; import com.github.manolo8.darkbot.config.actions.ValueData; -import com.github.manolo8.darkbot.config.actions.parser.ParseUtil; -import com.github.manolo8.darkbot.config.actions.parser.Values; +import com.github.manolo8.darkbot.config.actions.tree.ParsingNode; import com.github.manolo8.darkbot.core.utils.Location; import org.jetbrains.annotations.Nullable; @@ -26,17 +25,12 @@ public String toString() { } @Override - public String parse(String str) throws SyntaxException { - String[] params = str.split(" *, *", 2); - - double x = NumberConstant.parseNumber(params[0], str, getClass()).doubleValue(); - - params = (str = ParseUtil.separate(params, getClass(), ",")).split("\\)", 2); - double y = NumberConstant.parseNumber(params[0], str, getClass()).doubleValue(); + public void parse(ParsingNode node) throws SyntaxException { + node.requireParamSize(2, getClass()); + double x = NumberConstant.parseNumber(node.getParam(0), getClass()).doubleValue(); + double y = NumberConstant.parseNumber(node.getParam(1), getClass()).doubleValue(); location = new Location(x, y); - - return ParseUtil.separate(params, getClass(), ")"); } } diff --git a/src/main/java/com/github/manolo8/darkbot/config/actions/values/MapConstant.java b/src/main/java/com/github/manolo8/darkbot/config/actions/values/MapConstant.java index 2b10a6bdf..0e79fdeed 100644 --- a/src/main/java/com/github/manolo8/darkbot/config/actions/values/MapConstant.java +++ b/src/main/java/com/github/manolo8/darkbot/config/actions/values/MapConstant.java @@ -5,8 +5,8 @@ import com.github.manolo8.darkbot.config.actions.SyntaxException; import com.github.manolo8.darkbot.config.actions.Value; import com.github.manolo8.darkbot.config.actions.ValueData; -import com.github.manolo8.darkbot.config.actions.parser.ParseUtil; import com.github.manolo8.darkbot.config.actions.parser.Values; +import com.github.manolo8.darkbot.config.actions.tree.ParsingNode; import com.github.manolo8.darkbot.core.manager.HeroManager; import com.github.manolo8.darkbot.core.manager.StarManager; import com.github.manolo8.darkbot.core.objects.Map; @@ -35,28 +35,26 @@ public String toString() { } @Override - public String parse(String str) throws SyntaxException { - String[] params = str.split("\\)", 2); + public void parse(ParsingNode node) throws SyntaxException { + node.requireParamSize(1, getClass()); + String name = node.getParamStr(0); - params[0] = params[0].trim().toLowerCase(Locale.ROOT); map = StarManager.getAllMaps().stream() .filter(m -> m.id > 0) - .filter(m -> m.name.equalsIgnoreCase(params[0]) || - (m.shortName != null && m.shortName.equalsIgnoreCase(params[0]))) + .filter(m -> m.name.equalsIgnoreCase(name) || + (m.shortName != null && m.shortName.equalsIgnoreCase(name))) .findFirst().orElse(null); if (map == null) - throw new SyntaxException("Unknown map: '" + params[0] + "'", str, Values.getMeta(getClass()), + throw new SyntaxException("Unknown map: '" + name + "'", node.getParam(0), Values.getMeta(getClass()), StarManager.getAllMaps().stream() .filter(m -> m.id > 0) - .filter(m -> HeroManager.instance.map == m || (params[0].isEmpty() ? + .filter(m -> HeroManager.instance.map == m || (name.isEmpty() ? ACCESSIBLE_MAPS.contains(m.name) : - m.name.toLowerCase(Locale.ROOT).contains(params[0]))) + m.name.toLowerCase(Locale.ROOT).contains(name))) .map(m -> m.shortName != null ? m.shortName : m.name) .distinct() .toArray(String[]::new)); - - return ParseUtil.separate(params, getClass(), ")"); } } diff --git a/src/main/java/com/github/manolo8/darkbot/config/actions/values/NumberConstant.java b/src/main/java/com/github/manolo8/darkbot/config/actions/values/NumberConstant.java index be38de54d..6e93ed6bd 100644 --- a/src/main/java/com/github/manolo8/darkbot/config/actions/values/NumberConstant.java +++ b/src/main/java/com/github/manolo8/darkbot/config/actions/values/NumberConstant.java @@ -5,8 +5,8 @@ import com.github.manolo8.darkbot.config.actions.SyntaxException; import com.github.manolo8.darkbot.config.actions.Value; import com.github.manolo8.darkbot.config.actions.ValueData; -import com.github.manolo8.darkbot.config.actions.parser.ParseUtil; import com.github.manolo8.darkbot.config.actions.parser.Values; +import com.github.manolo8.darkbot.config.actions.tree.ParsingNode; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; @@ -39,21 +39,16 @@ public String toString() { } @Override - public String parse(String str) throws SyntaxException { - String[] params = str.split("\\)", 2); - - number = parseNumber(params[0], str, getClass()); - return ParseUtil.separate(params, getClass(), ")"); + public void parse(ParsingNode node) throws SyntaxException { + node.requireParamSize(1, getClass()); + number = parseNumber(node.getParam(0), getClass()); } - public static Number parseNumber(String val, String str, Class> type) throws SyntaxException { - if (val.isEmpty()) - throw new SyntaxException("Empty number, add digits", str, Values.getMeta(type)); - + public static Number parseNumber(ParsingNode node, Class> type) throws SyntaxException { try { - return NUMBER_FORMAT.parse(val); + return NUMBER_FORMAT.parse(node.getString()); } catch (ParseException e) { - throw new SyntaxException("Failed to parse number '" + val + "'", str, Values.getMeta(type)); + throw new SyntaxException("Failed to parse number '" + node.getFunction() + "'", node, Values.getMeta(type)); } } diff --git a/src/main/java/com/github/manolo8/darkbot/config/actions/values/PercentConstant.java b/src/main/java/com/github/manolo8/darkbot/config/actions/values/PercentConstant.java index faa789e24..4045a3e95 100644 --- a/src/main/java/com/github/manolo8/darkbot/config/actions/values/PercentConstant.java +++ b/src/main/java/com/github/manolo8/darkbot/config/actions/values/PercentConstant.java @@ -5,8 +5,8 @@ import com.github.manolo8.darkbot.config.actions.SyntaxException; import com.github.manolo8.darkbot.config.actions.Value; import com.github.manolo8.darkbot.config.actions.ValueData; -import com.github.manolo8.darkbot.config.actions.parser.ParseUtil; import com.github.manolo8.darkbot.config.actions.parser.Values; +import com.github.manolo8.darkbot.config.actions.tree.ParsingNode; @ValueData(name = "percent", description = "Creates a percent constant", example = "percent(5)") public class PercentConstant implements Value, Parser { @@ -24,18 +24,14 @@ public String toString() { } @Override - public String parse(String str) throws SyntaxException { - String[] params = str.split("\\)", 2); - - if (params[0].isEmpty()) - throw new SyntaxException("Empty percent, add digits", str, Values.getMeta(getClass())); + public void parse(ParsingNode node) throws SyntaxException { + node.requireParamSize(1, getClass()); + ParsingNode val = node.getParam(0); try { - percent = Double.parseDouble(params[0]) / 100; + percent = Double.parseDouble(val.getString()) / 100; } catch (NumberFormatException e) { - throw new SyntaxException("Failed to parse percent '" + params[0] + "'", str, Values.getMeta(getClass())); + throw new SyntaxException("Failed to parse percent '" + val.getFunction() + "'", val, Values.getMeta(getClass())); } - - return ParseUtil.separate(params, getClass(), ")"); } } diff --git a/src/main/java/com/github/manolo8/darkbot/config/actions/values/StatTypeValue.java b/src/main/java/com/github/manolo8/darkbot/config/actions/values/StatTypeValue.java index 9c6d3165e..0ed5b5096 100644 --- a/src/main/java/com/github/manolo8/darkbot/config/actions/values/StatTypeValue.java +++ b/src/main/java/com/github/manolo8/darkbot/config/actions/values/StatTypeValue.java @@ -5,7 +5,7 @@ import com.github.manolo8.darkbot.config.actions.SyntaxException; import com.github.manolo8.darkbot.config.actions.Value; import com.github.manolo8.darkbot.config.actions.ValueData; -import com.github.manolo8.darkbot.config.actions.parser.ParseUtil; +import com.github.manolo8.darkbot.config.actions.tree.ParsingNode; import eu.darkbot.api.game.stats.Stats; import eu.darkbot.api.managers.StatsAPI; import org.jetbrains.annotations.Nullable; @@ -35,11 +35,12 @@ public class StatTypeValue implements Value, Parser { } } - private Stats.General getKeyFromString(String key) { + private Stats.General getKeyFromString(ParsingNode node) { + String key = node.getString(); for (Stats.General stat : Stats.General.values()) { if (stat.name().equalsIgnoreCase(key)) return stat; } - return null; + throw new SyntaxException("Unknown stat-type: '" + key + "'", node, Stats.General.class); } public enum StatData { @@ -54,11 +55,12 @@ public String toString() { return name().toLowerCase(Locale.ROOT); } - public static StatData of(String sd) { - for (StatData statData : StatData.values()) { - if (statData.toString().equalsIgnoreCase(sd)) return statData; + public static StatData of(ParsingNode node) { + String statData = node.getString(); + for (StatData sd : StatData.values()) { + if (sd.toString().equalsIgnoreCase(statData)) return sd; } - return null; + throw new SyntaxException("Unknown stat data: '" + statData + "'", node, StatData.class); } } @@ -68,25 +70,12 @@ public String toString() { } @Override - public String parse(String str) throws SyntaxException { - String[] params = str.split(" *, *", 2); + public void parse(ParsingNode node) throws SyntaxException { + node.requireParamSize(2, getClass()); - key = getKeyFromString(params[0].trim()); + key = getKeyFromString(node.getParam(0)); + dataType = StatData.of(node.getParam(1)); stat = null; - - if (key == null) { - throw new SyntaxException("Unknown stat-type: '" + params[0] + "'", str, Stats.General.class); - } - - params = ParseUtil.separate(params, getClass(), ",").split("\\)", 2); - - dataType = StatData.of(params[0].trim()); - - if (dataType == null) { - throw new SyntaxException("Unknown data-type: '" + params[0] + "'", params[0], StatData.class); - } - - return ParseUtil.separate(params, getClass(), ")"); } } \ No newline at end of file diff --git a/src/main/java/com/github/manolo8/darkbot/config/actions/values/StringConstant.java b/src/main/java/com/github/manolo8/darkbot/config/actions/values/StringConstant.java index 4d52c5ee7..109efc707 100644 --- a/src/main/java/com/github/manolo8/darkbot/config/actions/values/StringConstant.java +++ b/src/main/java/com/github/manolo8/darkbot/config/actions/values/StringConstant.java @@ -5,9 +5,9 @@ import com.github.manolo8.darkbot.config.actions.SyntaxException; import com.github.manolo8.darkbot.config.actions.Value; import com.github.manolo8.darkbot.config.actions.ValueData; -import com.github.manolo8.darkbot.config.actions.parser.ParseUtil; +import com.github.manolo8.darkbot.config.actions.tree.ParsingNode; -@ValueData(name = "string", description = "String constant", example = "string(hello)") +@ValueData(name = "string", description = "String constant", example = "string(\"hello\")") public class StringConstant implements Value, Parser { public String string; @@ -19,19 +19,13 @@ public String get(Main main) { @Override public String toString() { - return "string(" + string.replace(")", "\\)") + ")"; + return "string(" + ParsingNode.escape(string) + ")"; } @Override - public String parse(String str) throws SyntaxException { - String[] params = str.split("(? start; + } + + @Override + public Position getEnd() { + return () -> end; + } + } +}