diff --git a/src/main/java/ch/njol/skript/conditions/CondAlphanumeric.java b/src/main/java/ch/njol/skript/conditions/CondAlphanumeric.java index 01702442428..f20e7467bd5 100644 --- a/src/main/java/ch/njol/skript/conditions/CondAlphanumeric.java +++ b/src/main/java/ch/njol/skript/conditions/CondAlphanumeric.java @@ -1,5 +1,7 @@ package ch.njol.skript.conditions; +import ch.njol.skript.lang.Literal; +import ch.njol.skript.lang.SimplifiedCondition; import org.apache.commons.lang.StringUtils; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; @@ -42,7 +44,14 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye public boolean check(Event e) { return isNegated() ^ strings.check(e, StringUtils::isAlphanumeric); } - + + @Override + public Condition simplify() { + if (strings instanceof Literal) + return SimplifiedCondition.fromCondition(this); + return this; + } + @Override public String toString(@Nullable Event e, boolean debug) { return strings.toString(e, debug) + " is" + (isNegated() ? "n't" : "") + " alphanumeric"; diff --git a/src/main/java/ch/njol/skript/conditions/CondCompare.java b/src/main/java/ch/njol/skript/conditions/CondCompare.java index 74e5f96e7ae..b7ec5aee9c7 100644 --- a/src/main/java/ch/njol/skript/conditions/CondCompare.java +++ b/src/main/java/ch/njol/skript/conditions/CondCompare.java @@ -10,6 +10,7 @@ import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.ExpressionList; import ch.njol.skript.lang.Literal; +import ch.njol.skript.lang.SimplifiedCondition; import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.lang.UnparsedLiteral; import ch.njol.skript.lang.VerboseAssert; @@ -397,6 +398,13 @@ private boolean compareLists(Event event) { return shouldMatch; } + @Override + public Condition simplify() { + if (first instanceof Literal && second instanceof Literal && (third == null || third instanceof Literal)) + return SimplifiedCondition.fromCondition(this); + return this; + } + @Override public String toString(final @Nullable Event event, final boolean debug) { String s; diff --git a/src/main/java/ch/njol/skript/conditions/CondContains.java b/src/main/java/ch/njol/skript/conditions/CondContains.java index 1aa5d9ac245..3965e5b0c8e 100644 --- a/src/main/java/ch/njol/skript/conditions/CondContains.java +++ b/src/main/java/ch/njol/skript/conditions/CondContains.java @@ -3,29 +3,30 @@ import ch.njol.skript.Skript; import ch.njol.skript.SkriptConfig; import ch.njol.skript.aliases.ItemType; -import ch.njol.skript.lang.VerboseAssert; -import ch.njol.skript.lang.util.common.AnyContains; -import ch.njol.skript.util.LiteralUtils; -import org.skriptlang.skript.lang.comparator.Relation; import ch.njol.skript.doc.Description; import ch.njol.skript.doc.Examples; import ch.njol.skript.doc.Name; import ch.njol.skript.doc.Since; import ch.njol.skript.lang.Condition; import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.Literal; +import ch.njol.skript.lang.SimplifiedCondition; import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.lang.VerboseAssert; import ch.njol.skript.lang.util.SimpleExpression; -import org.skriptlang.skript.lang.comparator.Comparators; +import ch.njol.skript.lang.util.common.AnyContains; +import ch.njol.skript.util.LiteralUtils; import ch.njol.util.Kleenean; import ch.njol.util.StringUtils; import org.bukkit.event.Event; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; -import org.skriptlang.skript.lang.converter.Converters; import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.lang.comparator.Comparators; +import org.skriptlang.skript.lang.comparator.Relation; +import org.skriptlang.skript.lang.converter.Converters; import java.util.Arrays; -import java.util.List; import java.util.Objects; import java.util.StringJoiner; @@ -183,6 +184,13 @@ public String getReceivedMessage(Event event) { return joiner.toString(); } + @Override + public Condition simplify() { + if (containers instanceof Literal && items instanceof Literal) + return SimplifiedCondition.fromCondition(this); + return this; + } + @Override public String toString(@Nullable Event e, boolean debug) { return containers.toString(e, debug) + (isNegated() ? " doesn't contain " : " contains ") + items.toString(e, debug); diff --git a/src/main/java/ch/njol/skript/conditions/CondDate.java b/src/main/java/ch/njol/skript/conditions/CondDate.java index 473dc9423b7..88b0086b596 100644 --- a/src/main/java/ch/njol/skript/conditions/CondDate.java +++ b/src/main/java/ch/njol/skript/conditions/CondDate.java @@ -1,5 +1,7 @@ package ch.njol.skript.conditions; +import ch.njol.skript.lang.Literal; +import ch.njol.skript.lang.SimplifiedCondition; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; @@ -58,7 +60,14 @@ public boolean check(final Event e) { timespan -> now - date.getTime() >= timespan.getAs(Timespan.TimePeriod.MILLISECOND) ), isNegated()); } - + + @Override + public Condition simplify() { + if (date instanceof Literal && delta instanceof Literal) + return SimplifiedCondition.fromCondition(this); + return this; + } + @Override public String toString(final @Nullable Event e, final boolean debug) { return date.toString(e, debug) + " was " + (isNegated() ? "less" : "more") + " than " + delta.toString(e, debug) + " ago"; diff --git a/src/main/java/ch/njol/skript/conditions/CondIsFuel.java b/src/main/java/ch/njol/skript/conditions/CondIsFuel.java index f124f183a6b..9a303e97c20 100644 --- a/src/main/java/ch/njol/skript/conditions/CondIsFuel.java +++ b/src/main/java/ch/njol/skript/conditions/CondIsFuel.java @@ -1,15 +1,16 @@ package ch.njol.skript.conditions; -import org.bukkit.Material; - import ch.njol.skript.Skript; import ch.njol.skript.aliases.ItemType; import ch.njol.skript.conditions.base.PropertyCondition; import ch.njol.skript.doc.Description; import ch.njol.skript.doc.Examples; import ch.njol.skript.doc.Name; -import ch.njol.skript.doc.RequiredPlugins; import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Condition; +import ch.njol.skript.lang.Literal; +import ch.njol.skript.lang.SimplifiedCondition; +import org.bukkit.Material; @Name("Is Fuel") @Description("Checks whether an item can be used as fuel in a furnace.") @@ -32,7 +33,14 @@ public class CondIsFuel extends PropertyCondition { public boolean check(ItemType item) { return item.getMaterial().isFuel(); } - + + @Override + public Condition simplify() { + if (getExpr() instanceof Literal) + return SimplifiedCondition.fromCondition(this); + return this; + } + @Override protected String getPropertyName() { return "fuel"; diff --git a/src/main/java/ch/njol/skript/conditions/CondIsInfinite.java b/src/main/java/ch/njol/skript/conditions/CondIsInfinite.java index 9d76f4b0d88..12e3fb944da 100644 --- a/src/main/java/ch/njol/skript/conditions/CondIsInfinite.java +++ b/src/main/java/ch/njol/skript/conditions/CondIsInfinite.java @@ -5,6 +5,9 @@ import ch.njol.skript.doc.Example; import ch.njol.skript.doc.Name; import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Condition; +import ch.njol.skript.lang.Literal; +import ch.njol.skript.lang.SimplifiedCondition; import ch.njol.skript.util.Timespan; import org.bukkit.potion.PotionEffect; @@ -28,6 +31,13 @@ public boolean check(Object object) { return false; } + @Override + public Condition simplify() { + if (getExpr() instanceof Literal) + return SimplifiedCondition.fromCondition(this); + return this; + } + @Override protected String getPropertyName() { return "infinite"; diff --git a/src/main/java/ch/njol/skript/conditions/CondIsVectorNormalized.java b/src/main/java/ch/njol/skript/conditions/CondIsVectorNormalized.java index 7c4851d8470..4267bad9992 100644 --- a/src/main/java/ch/njol/skript/conditions/CondIsVectorNormalized.java +++ b/src/main/java/ch/njol/skript/conditions/CondIsVectorNormalized.java @@ -5,6 +5,9 @@ import ch.njol.skript.doc.Examples; import ch.njol.skript.doc.Name; import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Condition; +import ch.njol.skript.lang.Literal; +import ch.njol.skript.lang.SimplifiedCondition; import org.bukkit.util.Vector; @Name("Is Normalized") @@ -21,7 +24,14 @@ public class CondIsVectorNormalized extends PropertyCondition { public boolean check(Vector vector) { return vector.isNormalized(); } - + + @Override + public Condition simplify() { + if (getExpr() instanceof Literal) + return SimplifiedCondition.fromCondition(this); + return this; + } + @Override protected String getPropertyName() { return "normalized"; diff --git a/src/main/java/ch/njol/skript/conditions/CondMatches.java b/src/main/java/ch/njol/skript/conditions/CondMatches.java index 6ce5facb581..d29643ffcc2 100644 --- a/src/main/java/ch/njol/skript/conditions/CondMatches.java +++ b/src/main/java/ch/njol/skript/conditions/CondMatches.java @@ -1,12 +1,6 @@ package ch.njol.skript.conditions; -import java.util.Arrays; -import java.util.regex.Pattern; - -import org.bukkit.event.Event; -import org.jetbrains.annotations.Nullable; - import ch.njol.skript.Skript; import ch.njol.skript.doc.Description; import ch.njol.skript.doc.Examples; @@ -14,8 +8,15 @@ import ch.njol.skript.doc.Since; import ch.njol.skript.lang.Condition; import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.Literal; +import ch.njol.skript.lang.SimplifiedCondition; import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.util.Kleenean; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.regex.Pattern; @Name("Matches") @Description("Checks whether the defined strings match the input regexes (Regular expressions).") @@ -75,7 +76,14 @@ public boolean check(Event e) { public boolean matches(String str, Pattern pattern) { return partial ? pattern.matcher(str).find() : str.matches(pattern.pattern()); } - + + @Override + public Condition simplify() { + if (strings instanceof Literal && regex instanceof Literal) + return SimplifiedCondition.fromCondition(this); + return this; + } + @Override public String toString(@Nullable Event e, boolean debug) { return strings.toString(e, debug) + " " + (isNegated() ? "doesn't match" : "matches") + " " + regex.toString(e, debug); diff --git a/src/main/java/ch/njol/skript/conditions/CondMinecraftVersion.java b/src/main/java/ch/njol/skript/conditions/CondMinecraftVersion.java index 682b6a144cd..6160a400219 100644 --- a/src/main/java/ch/njol/skript/conditions/CondMinecraftVersion.java +++ b/src/main/java/ch/njol/skript/conditions/CondMinecraftVersion.java @@ -1,5 +1,7 @@ package ch.njol.skript.conditions; +import ch.njol.skript.lang.Literal; +import ch.njol.skript.lang.SimplifiedCondition; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; @@ -40,7 +42,14 @@ public boolean check(Event e) { String ver = version.getSingle(e); return ver != null ? Skript.isRunningMinecraft(new Version(ver)) ^ isNegated() : false; } - + + @Override + public Condition simplify() { + if (version instanceof Literal) + return SimplifiedCondition.fromCondition(this); + return this; + } + @Override public String toString(@Nullable Event e, boolean debug) { return "is running minecraft " + version.toString(e, debug); diff --git a/src/main/java/ch/njol/skript/conditions/CondPastFuture.java b/src/main/java/ch/njol/skript/conditions/CondPastFuture.java index 2f8748f1a73..916a35e653a 100644 --- a/src/main/java/ch/njol/skript/conditions/CondPastFuture.java +++ b/src/main/java/ch/njol/skript/conditions/CondPastFuture.java @@ -9,6 +9,8 @@ import ch.njol.skript.lang.Condition; import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.ExpressionList; +import ch.njol.skript.lang.Literal; +import ch.njol.skript.lang.SimplifiedCondition; import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.util.Date; import ch.njol.util.Kleenean; @@ -78,6 +80,13 @@ public boolean check(Event event) { return dates.check(event, date -> date.compareTo(new Date()) < 0, isNegated()); } + @Override + public Condition simplify() { + if (dates instanceof Literal) + return SimplifiedCondition.fromCondition(this); + return this; + } + @Override public String toString(@Nullable Event event, boolean debug) { return dates.toString(event, debug) + (dates.isSingle() ? " is" : " are") + " in the" + (isFuture ? " future" : " past"); diff --git a/src/main/java/ch/njol/skript/conditions/CondStartsEndsWith.java b/src/main/java/ch/njol/skript/conditions/CondStartsEndsWith.java index 205db7eca53..463b3d837f5 100644 --- a/src/main/java/ch/njol/skript/conditions/CondStartsEndsWith.java +++ b/src/main/java/ch/njol/skript/conditions/CondStartsEndsWith.java @@ -1,5 +1,7 @@ package ch.njol.skript.conditions; +import ch.njol.skript.lang.Literal; +import ch.njol.skript.lang.SimplifiedCondition; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; @@ -80,7 +82,14 @@ public boolean check(Event e) { }, isNegated()); } - + + @Override + public Condition simplify() { + if (strings instanceof Literal && affix instanceof Literal) + return SimplifiedCondition.fromCondition(this); + return this; + } + @Override public String toString(@Nullable Event e, boolean debug) { if (isNegated()) diff --git a/src/main/java/ch/njol/skript/lang/Condition.java b/src/main/java/ch/njol/skript/lang/Condition.java index 40f76710124..9e130d013e9 100644 --- a/src/main/java/ch/njol/skript/lang/Condition.java +++ b/src/main/java/ch/njol/skript/lang/Condition.java @@ -3,6 +3,7 @@ import ch.njol.skript.Skript; import ch.njol.skript.conditions.base.PropertyCondition; import ch.njol.skript.config.Node; +import ch.njol.skript.lang.simplification.Simplifiable; import ch.njol.skript.lang.util.SimpleExpression; import ch.njol.util.Kleenean; import org.bukkit.event.Event; @@ -22,7 +23,7 @@ * * @see Skript#registerCondition(Class, String...) */ -public abstract class Condition extends Statement implements Conditional, SyntaxRuntimeErrorProducer { +public abstract class Condition extends Statement implements Conditional, SyntaxRuntimeErrorProducer, Simplifiable { public enum ConditionType { /** @@ -117,6 +118,11 @@ public Node getNode() { return "condition"; } + @Override + public Condition simplify() { + return this; + } + /** * Parse a raw string input as a condition. * diff --git a/src/main/java/ch/njol/skript/lang/SimplifiedCondition.java b/src/main/java/ch/njol/skript/lang/SimplifiedCondition.java new file mode 100644 index 00000000000..6a9562660f3 --- /dev/null +++ b/src/main/java/ch/njol/skript/lang/SimplifiedCondition.java @@ -0,0 +1,99 @@ +package ch.njol.skript.lang; + +import ch.njol.skript.Skript; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.lang.parser.ParserInstance; +import ch.njol.skript.lang.util.ContextlessEvent; +import ch.njol.skript.test.runner.TestMode; +import ch.njol.util.Kleenean; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.lang.script.Script; +import org.skriptlang.skript.lang.script.ScriptWarning; + +/** + * Represents a condition that can be simplified during initialization. + */ +public class SimplifiedCondition extends Condition { + + /** + * Creates a new {@link SimplifiedCondition} from a {@link Condition} by evaluating it with a {@link ContextlessEvent}. + * Any expression used by {@code original} that requires specific event data cannot be safely simplified. + * + * @param original The original {@link Condition} to simplify. + * @return A new {@link SimplifiedCondition}. + */ + public static Condition fromCondition(Condition original) { + return fromCondition(original, (!TestMode.ENABLED || TestMode.DEV_MODE)); + } + + /** + * Creates a new {@link SimplifiedCondition} from a {@link Condition} by evaluating it with a {@link ContextlessEvent}. + * Any expression used by {@code original} that requires specific event data cannot be safely simplified. + * + * @param original The original {@link Condition} to simplify. + * @param warn Whether a warning for constant conditions should be outputted. + * @return A new {@link SimplifiedCondition}. + */ + public static Condition fromCondition(Condition original, boolean warn) { + if (original instanceof SimplifiedCondition simplifiedCondition) + return simplifiedCondition; + + Event event = ContextlessEvent.get(); + boolean result = original.check(event); + + if (warn) { + ParserInstance parser = ParserInstance.get(); + Script script = parser.isActive() ? parser.getCurrentScript() : null; + if (script != null && !script.suppressesWarning(ScriptWarning.CONSTANT_CONDITION)) { + Skript.warning("The condition '" + original.toString(event, Skript.debug()) + "' will always be " + (result ? "true" : "false") + "."); + } + } + + return new SimplifiedCondition(original, result); + } + + private final Condition source; + private final boolean result; + + /** + * Constructs a new {@link SimplifiedCondition}. + * + * @param source The source {@link Condition} this was created from. + * @param result The evaluated result from {@code source} via {@link Condition#check(Event)}. + */ + private SimplifiedCondition(Condition source, boolean result) { + this.source = source; + this.result = result; + } + + /** + * Returns the source {@link Condition} used to create this {@link SimplifiedCondition}. + */ + public Condition getSource() { + return source; + } + + /** + * Returns the result that was evaluated from {@link #source} during initialization. + */ + public boolean getResult() { + return result; + } + + @Override + public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean check(Event event) { + return result; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return source.toString(event, debug); + } + +} diff --git a/src/main/java/ch/njol/skript/test/runner/CondMethodExists.java b/src/main/java/ch/njol/skript/test/runner/CondMethodExists.java index a479fcb903c..f7b9307569e 100644 --- a/src/main/java/ch/njol/skript/test/runner/CondMethodExists.java +++ b/src/main/java/ch/njol/skript/test/runner/CondMethodExists.java @@ -2,6 +2,9 @@ import ch.njol.skript.conditions.base.PropertyCondition; import ch.njol.skript.doc.NoDoc; +import ch.njol.skript.lang.Condition; +import ch.njol.skript.lang.Literal; +import ch.njol.skript.lang.SimplifiedCondition; import org.apache.commons.lang.StringUtils; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; @@ -71,6 +74,13 @@ protected String getPropertyName() { return "method exists"; } + @Override + public Condition simplify() { + if (!(signatures instanceof Literal)) + return this; + return SimplifiedCondition.fromCondition(this); + } + @Override public String toString(@Nullable Event event, boolean debug) { return "method " + signatures.toString(event, debug) + " exists"; diff --git a/src/main/java/org/skriptlang/skript/lang/script/ScriptWarning.java b/src/main/java/org/skriptlang/skript/lang/script/ScriptWarning.java index 847cde014b6..1338040cb1d 100644 --- a/src/main/java/org/skriptlang/skript/lang/script/ScriptWarning.java +++ b/src/main/java/org/skriptlang/skript/lang/script/ScriptWarning.java @@ -1,7 +1,9 @@ package org.skriptlang.skript.lang.script; import ch.njol.skript.Skript; +import ch.njol.skript.lang.Condition; import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SimplifiedCondition; import ch.njol.skript.lang.SkriptParser; import ch.njol.skript.lang.parser.ParserInstance; import ch.njol.util.Kleenean; @@ -41,7 +43,13 @@ public enum ScriptWarning { /** * The code cannot be reached due to a previous statement stopping further execution */ - UNREACHABLE_CODE("unreachable code"); + UNREACHABLE_CODE("unreachable code"), + + /** + * A {@link Condition} can be simplified to {@link SimplifiedCondition}, which results in the assertion always passing or failing. + */ + CONSTANT_CONDITION("constant condition", "constant condition[s]") + ; private final String warningName; private final String pattern;