diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..772fe705c --- /dev/null +++ b/.editorconfig @@ -0,0 +1,23 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = true +max_line_length = 120 +tab_width = 4 +trim_trailing_whitespace = true +ij_continuation_indent_size = 4 +[*.java] +ij_java_class_count_to_use_import_on_demand = 1024 +ij_java_names_count_to_use_import_on_demand = 1024 +[*.yml] +indent_size = 2 +[*.json] +indent_size = 2 +[*.md] +trim_trailing_whitespace=false +[*.sk] +indent_style = tab diff --git a/build.gradle.kts b/build.gradle.kts index fd38e5a5a..f2d425af1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,6 +1,7 @@ plugins { id("java") id("maven-publish") + id("checkstyle") } group = "com.github.SkriptDev" version = "1.0.6" @@ -56,6 +57,17 @@ tasks { java { withSourcesJar() } + checkstyle { + // Specify the version of the Checkstyle tool to use + toolVersion = "10.21.0" // Use a recent version of Checkstyle + + isIgnoreFailures = false + + // Point to your custom Checkstyle configuration file + // The default location is config/checkstyle/checkstyleMain.xml + configFile = file("${rootProject.projectDir}/config/checkstyle/checkstyle.xml") + } + publishing { publications { create("maven") { diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml new file mode 100644 index 000000000..22c57fb38 --- /dev/null +++ b/config/checkstyle/checkstyle.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/io/github/syst3ms/skriptparser/effects/EffEscape.java b/src/main/java/io/github/syst3ms/skriptparser/effects/EffEscape.java index b8a9d3132..8dd7b33be 100644 --- a/src/main/java/io/github/syst3ms/skriptparser/effects/EffEscape.java +++ b/src/main/java/io/github/syst3ms/skriptparser/effects/EffEscape.java @@ -63,7 +63,7 @@ public Optional walk(TriggerContext ctx) { ? ((SelfReferencing) val).getActualNext() : val.getNext()); - // Because otherwise SelfReferencing sections will first reference to themselves + // Because otherwise SelfReferencing sections will getFirst reference to themselves if (current.filter(val -> val instanceof Finishing).isEmpty()) am--; } diff --git a/src/main/java/io/github/syst3ms/skriptparser/effects/EffExit.java b/src/main/java/io/github/syst3ms/skriptparser/effects/EffExit.java index 8b0647d1f..690ef6d63 100644 --- a/src/main/java/io/github/syst3ms/skriptparser/effects/EffExit.java +++ b/src/main/java/io/github/syst3ms/skriptparser/effects/EffExit.java @@ -39,7 +39,10 @@ public class EffExit extends Effect { "(exit|stop) %*integer% (0:section|1:loop|2:condition[al])[s]", "(exit|stop) (every|all [[of] the]) (0:section|1:loop|2:condition[al])[s]") .name("Exit") - .description("Exits the entire trigger, preventing all upcoming statements to not get triggered. There's also a possibility to only exit certain sections. If more sections are exited than the total amount of nested sections, the trigger will stop. Note that stopping loops also stops while-loops.") + .description("Exits the entire trigger, preventing all upcoming statements to not get triggered", + "There's also a possibility to only exit certain sections.", + "If more sections are exited than the total amount of nested sections, the trigger will stop.", + "Note that stopping loops also stops while-loops.") .since("1.0.0") .register(); } diff --git a/src/main/java/io/github/syst3ms/skriptparser/effects/EffReturn.java b/src/main/java/io/github/syst3ms/skriptparser/effects/EffReturn.java index 8a7d6f834..e50d45abe 100644 --- a/src/main/java/io/github/syst3ms/skriptparser/effects/EffReturn.java +++ b/src/main/java/io/github/syst3ms/skriptparser/effects/EffReturn.java @@ -114,7 +114,7 @@ public Optional walk(TriggerContext ctx) { }); if (isInFunction) { FunctionContext functionContext = (FunctionContext) ctx; - Function function = functionContext.getOwningFunction(); + Function function = functionContext.owningFunction(); function.setReturnValue(returned.getValues(ctx)); return Optional.empty(); // stop the trigger } diff --git a/src/main/java/io/github/syst3ms/skriptparser/expressions/CondExprChance.java b/src/main/java/io/github/syst3ms/skriptparser/expressions/CondExprChance.java index 801f09412..2540e2ac3 100644 --- a/src/main/java/io/github/syst3ms/skriptparser/expressions/CondExprChance.java +++ b/src/main/java/io/github/syst3ms/skriptparser/expressions/CondExprChance.java @@ -10,6 +10,8 @@ public class CondExprChance extends ConditionalExpression { + private static final ThreadLocalRandom RANDOM = ThreadLocalRandom.current(); + static { Parser.getMainRegistration().newExpression(CondExprChance.class, Boolean.class, true, "chance of %number%[1:\\%]") @@ -22,8 +24,6 @@ public class CondExprChance extends ConditionalExpression { .register(); } - private static final ThreadLocalRandom RANDOM = ThreadLocalRandom.current(); - private Expression chance; private boolean percent; diff --git a/src/main/java/io/github/syst3ms/skriptparser/expressions/CondExprCompare.java b/src/main/java/io/github/syst3ms/skriptparser/expressions/CondExprCompare.java index f3cef0f55..9bf39f86d 100644 --- a/src/main/java/io/github/syst3ms/skriptparser/expressions/CondExprCompare.java +++ b/src/main/java/io/github/syst3ms/skriptparser/expressions/CondExprCompare.java @@ -40,14 +40,14 @@ */ public class CondExprCompare extends ConditionalExpression { public static final PatternInfos PATTERNS = new PatternInfos<>(new Object[][]{ - {"[1:neither] %objects% [8:each] ((is|are)(2:(n't [8:each]|[8: each] not|4:[8: each] neither)| [8:each]) (greater|more|higher|bigger|larger|above) [than] or (equal to|the same as)|\\>=) %objects% [0x10:each|0x18:respectively]", Relation.GREATER_OR_EQUAL}, - {"[1:neither] %objects% [8:each] ((is|are)(2:(n't [8:each]|[8: each] not|4:[8: each] neither)| [8:each]) (less|smaller|below) [than] or (equal to|the same as)|\\<=) %objects% [0x10:each|0x18:respectively]", Relation.SMALLER_OR_EQUAL}, - {"[1:neither] %objects% [8:each] ((is|are)(2:(n't [8:each]|[8: each] not|4:[8: each] neither)| [8:each]) ((greater|more|higher|bigger|larger) than|above)|\\>) %objects% [0x10:each|0x18:respectively]", Relation.GREATER}, - {"[1:neither] %objects% [8:each] ((is|are)(2:(n't [8:each]|[8: each] not|4:[8: each] neither)| [8:each]) ((less|smaller) than|below)|\\<) %objects% [0x10:each|0x18:respectively]", Relation.SMALLER}, - {"[1:neither] %objects% [8:each] (is|are)(2:n't [8:each]|2:[8: each] not) between %objects% and %objects% [0x10:each|0x18:respectively]", Relation.EQUAL}, - {"[1:neither] %objects% [8:each] (is|are) [8:each] between %objects% and %objects% [0x10:each|0x18:respectively]", Relation.EQUAL}, - {"[1:neither] %objects% [8:each] ((is|are)(2:(n't [8:each]|[8: each] not|4:[8: each] neither)) [equal to]|2:!=) %objects% [0x10:each|0x18:respectively]", Relation.EQUAL}, - {"[1:neither] %objects% [8:each] ((is|are) [8:each] [equal to|the same as]|=[=]) %objects% [0x10:each|0x18:respectively]", Relation.EQUAL} + {"[1:neither] %objects% [8:each] ((is|are)(2:(n't [8:each]|[8: each] not|4:[8: each] neither)| [8:each]) (greater|more|higher|bigger|larger|above) [than] or (equal to|the same as)|\\>=) %objects% [0x10:each|0x18:respectively]", Relation.GREATER_OR_EQUAL}, + {"[1:neither] %objects% [8:each] ((is|are)(2:(n't [8:each]|[8: each] not|4:[8: each] neither)| [8:each]) (less|smaller|below) [than] or (equal to|the same as)|\\<=) %objects% [0x10:each|0x18:respectively]", Relation.SMALLER_OR_EQUAL}, + {"[1:neither] %objects% [8:each] ((is|are)(2:(n't [8:each]|[8: each] not|4:[8: each] neither)| [8:each]) ((greater|more|higher|bigger|larger) than|above)|\\>) %objects% [0x10:each|0x18:respectively]", Relation.GREATER}, + {"[1:neither] %objects% [8:each] ((is|are)(2:(n't [8:each]|[8: each] not|4:[8: each] neither)| [8:each]) ((less|smaller) than|below)|\\<) %objects% [0x10:each|0x18:respectively]", Relation.SMALLER}, + {"[1:neither] %objects% [8:each] (is|are)(2:n't [8:each]|2:[8: each] not) between %objects% and %objects% [0x10:each|0x18:respectively]", Relation.EQUAL}, + {"[1:neither] %objects% [8:each] (is|are) [8:each] between %objects% and %objects% [0x10:each|0x18:respectively]", Relation.EQUAL}, + {"[1:neither] %objects% [8:each] ((is|are)(2:(n't [8:each]|[8: each] not|4:[8: each] neither)) [equal to]|2:!=) %objects% [0x10:each|0x18:respectively]", Relation.EQUAL}, + {"[1:neither] %objects% [8:each] ((is|are) [8:each] [equal to|the same as]|=[=]) %objects% [0x10:each|0x18:respectively]", Relation.EQUAL} }); static { @@ -74,6 +74,14 @@ public class CondExprCompare extends ConditionalExpression { private boolean firstEach; private boolean secondEach; + private static String errorString(Expression expr, boolean debug) { + if (expr.getReturnType() == Object.class) + return expr.toString(TriggerContext.DUMMY, debug); + Optional> exprType = TypeManager.getByClass(expr.getReturnType()); + assert exprType.isPresent(); + return StringUtils.withIndefiniteArticle(exprType.get().getBaseName(), !expr.isSingle()); + } + @SuppressWarnings("null") @Override public boolean init(Expression[] expressions, int matchedPattern, ParseContext result) { @@ -88,7 +96,7 @@ public boolean init(Expression[] expressions, int matchedPattern, ParseContex setNegated(true); if ((parseMark & 1) != 0) // "neither" on the left side setNegated(!isNegated()); - if ((parseMark & 4) != 0) {// "neither" on the right side + if ((parseMark & 4) != 0) { // "neither" on the right side if (second instanceof ExpressionList) { second.setAndList(!second.isAndList()); } @@ -101,42 +109,42 @@ public boolean init(Expression[] expressions, int matchedPattern, ParseContex if (firstEach && secondEach && first.isSingle() && second.isSingle() && (third == null || third.isSingle())) { logger.warn("Using \"respectively\" or two \"each\" options on single values is redundant"); } else if (firstEach - && secondEach - && (first.isAndList() != second.isAndList() || - first.isSingle() != second.isSingle())) { + && secondEach + && (first.isAndList() != second.isAndList() || + first.isSingle() != second.isSingle())) { /* * Here we want to rule out some obviously impossible combinations: * - Respectively comparing a single value and a list * - Respectively comparing lists that aren't both "and" or "or" */ logger.error( - "'" + - first.toString(TriggerContext.DUMMY, logger.isDebug()) + - "' and '" + - second.toString(TriggerContext.DUMMY, logger.isDebug()) + - "' cannot be compared respectively", - ErrorType.SEMANTIC_ERROR + "'" + + first.toString(TriggerContext.DUMMY, logger.isDebug()) + + "' and '" + + second.toString(TriggerContext.DUMMY, logger.isDebug()) + + "' cannot be compared respectively", + ErrorType.SEMANTIC_ERROR ); return false; } else if (third != null - && secondEach - && (firstEach && first.isAndList() != second.isAndList() - || second.isAndList() != third.isAndList() - || firstEach && first.isSingle() != second.isSingle() - || second.isSingle() != third.isSingle())) { + && secondEach + && (firstEach && first.isAndList() != second.isAndList() + || second.isAndList() != third.isAndList() + || firstEach && first.isSingle() != second.isSingle() + || second.isSingle() != third.isSingle())) { /* - * What is ruled out here is using "each" when "second" and "third" don't match in number or in and/or type. + * What is ruled out here is using "each" when "getSecond" and "third" don't match in number or in and/or type. * Otherwise these are fundamentally the same checks as above but when "third" is present. */ logger.error( - "'" + - first.toString(TriggerContext.DUMMY, logger.isDebug()) + - "' cannot be compared respectively with '" + - second.toString(TriggerContext.DUMMY, logger.isDebug()) + - "' and '" + - third.toString(TriggerContext.DUMMY, logger.isDebug()) + - "'", - ErrorType.SEMANTIC_ERROR + "'" + + first.toString(TriggerContext.DUMMY, logger.isDebug()) + + "' cannot be compared respectively with '" + + second.toString(TriggerContext.DUMMY, logger.isDebug()) + + "' and '" + + third.toString(TriggerContext.DUMMY, logger.isDebug()) + + "'", + ErrorType.SEMANTIC_ERROR ); return false; } else if (firstEach && first.isSingle()) { @@ -164,30 +172,30 @@ public boolean init(Expression[] expressions, int matchedPattern, ParseContex * two lists order-insensitively. */ contentComparison = third == null - && relation == Relation.EQUAL - && !(firstEach || secondEach) - && !(first.isSingle() || second.isSingle()); + && relation == Relation.EQUAL + && !(firstEach || secondEach) + && !(first.isSingle() || second.isSingle()); if (!initComparator()) { if (third == null) { logger.error( - "'" + + "'" + first.toString(TriggerContext.DUMMY, logger.isDebug()) + "' and '" + second.toString(TriggerContext.DUMMY, logger.isDebug()) + "' cannot be compared", - ErrorType.SEMANTIC_ERROR + ErrorType.SEMANTIC_ERROR ); } else { logger.error( - "'" + + "'" + first.toString(TriggerContext.DUMMY, logger.isDebug()) + "' cannot be compared with '" + second.toString(TriggerContext.DUMMY, logger.isDebug()) + "' and '" + third.toString(TriggerContext.DUMMY, logger.isDebug()) + "'", - ErrorType.SEMANTIC_ERROR + ErrorType.SEMANTIC_ERROR ); } return false; @@ -197,7 +205,7 @@ public boolean init(Expression[] expressions, int matchedPattern, ParseContex return relation.isEqualOrInverse() || comparator.supportsOrdering(); } else if (!comparator.supportsOrdering()) { logger.error( - errorString(first, logger.isDebug()) + + errorString(first, logger.isDebug()) + " cannot be ordered between " + errorString(second, logger.isDebug()) + " and " + @@ -212,8 +220,8 @@ public boolean init(Expression[] expressions, int matchedPattern, ParseContex private boolean initComparator() { Class f = first.getReturnType(); Class s = third == null - ? second.getReturnType() - : ClassUtils.getCommonSuperclass(second.getReturnType(), third.getReturnType()); + ? second.getReturnType() + : ClassUtils.getCommonSuperclass(second.getReturnType(), third.getReturnType()); if (f == Object.class || s == Object.class) { return true; @@ -221,40 +229,6 @@ private boolean initComparator() { return (comparator = (Comparator) Comparators.getComparator(f, s).orElse(null)) != null; } - /* - * # := condition (e.g. is, is less than, contains, is enchanted with, has permission, etc.) - * !# := not # - * - * a and b # x === a # x && b # x - * a or b # x === a # x || b # x - * a # x and y === a # x && a # y - * a # x or y === a # x || a # y - * a and b # x and y === a # x and y && b # x and y === a # x && a # y && b # x && b # y - * a and b # x or y === a # x or y && b # x or y - * a or b # x and y === a # x and y || b # x and y - * a or b # x or y === a # x or y || b # x or y - * - * - * a and b !# x === a !# x && b !# x - * neither a nor b # x === a !# x && b !# x // nor = and - * a or b !# x === a !# x || b !# x - * - * a !# x and y === a !# x || a !# y // e.g. "player doesn't have 2 emeralds and 5 gold ingots" == "NOT(player has 2 emeralds and 5 gold ingots)" == "player doesn't have 2 emeralds OR player doesn't have 5 gold ingots" - * a # neither x nor y === a !# x && a !# y // nor = or // e.g. "player has neither 2 emeralds nor 5 gold ingots" == "player doesn't have 2 emeralds AND player doesn't have 5 gold ingots" - * a # neither x nor y === a !# x && a !# y // nor = or // e.g. "player is neither the attacker nor the victim" == "player is not the attacker AND player is not the victim" - * a !# x or y === a !# x && a !# y // e.g. "player doesn't have 2 emeralds or 5 gold ingots" == "NOT(player has 2 emeralds or 5 gold ingots)" == "player doesn't have 2 emeralds AND player doesn't have 5 gold ingots" - * - * a and b !# x and y === a !# x and y && b !# x and y === (a !# x || a !# y) && (b !# x || b !# y) - * a and b !# x or y === a !# x or y && b !# x or y - * a and b # neither x nor y === a # neither x nor y && b # neither x nor y - * - * a or b !# x and y === a !# x and y || b !# x and y - * a or b !# x or y === a !# x or y || b !# x or y - * a or b # neither x nor y === a # neither x nor y || b # neither x nor y - * - * neither a nor b # x and y === a !# x and y && b !# x and y // nor = and - * neither a nor b # x or y === a !# x or y && b !# x or y // nor = and - */ @Override public boolean check(TriggerContext ctx) { Object[] firstValues = first.getArray(ctx); @@ -270,8 +244,8 @@ public boolean check(TriggerContext ctx) { for (int i = 0; i < firstValues.length; i++) { hasElement = true; boolean b = fullCompare( - Arrays.copyOfRange(firstValues, i, i+1), - Arrays.copyOfRange(secondValues, i, i+1) + Arrays.copyOfRange(firstValues, i, i + 1), + Arrays.copyOfRange(secondValues, i, i + 1) ); if (and && !b) return false; @@ -285,17 +259,17 @@ public boolean check(TriggerContext ctx) { return hasElement && and; } else if (firstEach) { return Expression.check( - firstValues, - f -> fullCompare(new Object[]{f}, secondValues), - false, - first.isAndList() + firstValues, + f -> fullCompare(new Object[]{f}, secondValues), + false, + first.isAndList() ); } else if (secondEach) { return Expression.check( - secondValues, - s -> fullCompare(firstValues, new Object[]{s}), - false, - second.isAndList() + secondValues, + s -> fullCompare(firstValues, new Object[]{s}), + false, + second.isAndList() ); } else { return fullCompare(firstValues, secondValues); @@ -309,9 +283,9 @@ public boolean check(TriggerContext ctx) { for (int i = 0; i < firstValues.length; i++) { hasElement = true; boolean b = fullCompareWithThird( - Arrays.copyOfRange(firstValues, i, i+1), - Arrays.copyOfRange(secondValues, i, i+1), - Arrays.copyOfRange(thirdValues, i, i+1) + Arrays.copyOfRange(firstValues, i, i + 1), + Arrays.copyOfRange(secondValues, i, i + 1), + Arrays.copyOfRange(thirdValues, i, i + 1) ); if (and && !b) return false; @@ -321,10 +295,10 @@ public boolean check(TriggerContext ctx) { return hasElement && and; } else if (firstEach) { return Expression.check( - firstValues, - f -> fullCompareWithThird(new Object[]{f}, secondValues, thirdValues), - false, - first.isAndList() + firstValues, + f -> fullCompareWithThird(new Object[]{f}, secondValues, thirdValues), + false, + first.isAndList() ); } else if (secondEach) { if (secondValues.length != thirdValues.length) @@ -335,9 +309,9 @@ public boolean check(TriggerContext ctx) { for (int i = 0; i < secondValues.length; i++) { hasElement = true; boolean b = fullCompareWithThird( - firstValues, - Arrays.copyOfRange(secondValues, i, i+1), - Arrays.copyOfRange(thirdValues, i, i+1) + firstValues, + Arrays.copyOfRange(secondValues, i, i + 1), + Arrays.copyOfRange(thirdValues, i, i + 1) ); if (and && !b) return false; @@ -353,19 +327,19 @@ public boolean check(TriggerContext ctx) { private boolean fullCompare(Object[] firstValues, Object[] secondValues) { if (!contentComparison) { return Expression.check( - firstValues, - o1 -> Expression.check( - secondValues, - o2 -> relation.is( - comparator != null ? - comparator.apply(o1, o2) - : Comparators.compare(o1, o2) - ), - false, - second.isAndList() + firstValues, + o1 -> Expression.check( + secondValues, + o2 -> relation.is( + comparator != null ? + comparator.apply(o1, o2) + : Comparators.compare(o1, o2) ), - isNegated(), - first.isAndList() + false, + second.isAndList() + ), + isNegated(), + first.isAndList() ); } else { if (firstValues.length != secondValues.length) @@ -393,38 +367,38 @@ private boolean fullCompare(Object[] firstValues, Object[] secondValues) { private boolean fullCompareWithThird(Object[] firstValues, Object[] secondValues, Object[] thirdValues) { assert third != null; return Expression.check( - firstValues, - o1 -> Expression.check( - secondValues, - o2 -> Expression.check( - thirdValues, - o3 -> { - boolean isBetween; - if (comparator != null) { - isBetween = - (Relation.GREATER_OR_EQUAL.is(comparator.apply(o1, o2)) && - Relation.SMALLER_OR_EQUAL.is(comparator.apply(o1, o3))) - || // Check OPPOSITE (switching o2 / o3) - (Relation.GREATER_OR_EQUAL.is(comparator.apply(o1, o3)) && - Relation.SMALLER_OR_EQUAL.is(comparator.apply(o1, o2))); - } else { - isBetween = - (Relation.GREATER_OR_EQUAL.is(Comparators.compare(o1, o2)) && - Relation.SMALLER_OR_EQUAL.is(Comparators.compare(o1, o3))) - || // Check OPPOSITE (switching o2 / o3) - (Relation.GREATER_OR_EQUAL.is(Comparators.compare(o1, o3)) && - Relation.SMALLER_OR_EQUAL.is(Comparators.compare(o1, o2))); - } - return relation == Relation.NOT_EQUAL != isBetween; - }, - false, - third.isAndList() - ), - false, - second.isAndList() + firstValues, + o1 -> Expression.check( + secondValues, + o2 -> Expression.check( + thirdValues, + o3 -> { + boolean isBetween; + if (comparator != null) { + isBetween = + (Relation.GREATER_OR_EQUAL.is(comparator.apply(o1, o2)) && + Relation.SMALLER_OR_EQUAL.is(comparator.apply(o1, o3))) + || // Check OPPOSITE (switching o2 / o3) + (Relation.GREATER_OR_EQUAL.is(comparator.apply(o1, o3)) && + Relation.SMALLER_OR_EQUAL.is(comparator.apply(o1, o2))); + } else { + isBetween = + (Relation.GREATER_OR_EQUAL.is(Comparators.compare(o1, o2)) && + Relation.SMALLER_OR_EQUAL.is(Comparators.compare(o1, o3))) + || // Check OPPOSITE (switching o2 / o3) + (Relation.GREATER_OR_EQUAL.is(Comparators.compare(o1, o3)) && + Relation.SMALLER_OR_EQUAL.is(Comparators.compare(o1, o2))); + } + return relation == Relation.NOT_EQUAL != isBetween; + }, + false, + third.isAndList() ), - isNegated(), - first.isAndList() + false, + second.isAndList() + ), + isNegated(), + first.isAndList() ); } @@ -434,27 +408,19 @@ public String toString(TriggerContext ctx, boolean debug) { Expression third = this.third; if (third == null) { s = first.toString(ctx, debug) + " is " + (isNegated() ? "not " : "") + relation + " " + second.toString( - ctx, debug); + ctx, debug); } else { s = first.toString(ctx, debug) + - " is " + - (isNegated() ? "not " : "") + - "between " + - second.toString(ctx, debug) + - " and " + - third.toString(ctx, debug); + " is " + + (isNegated() ? "not " : "") + + "between " + + second.toString(ctx, debug) + + " and " + + third.toString(ctx, debug); } if (debug) { s += " (comparator: " + comparator + ")"; } return s; } - - private static String errorString(Expression expr, boolean debug) { - if (expr.getReturnType() == Object.class) - return expr.toString(TriggerContext.DUMMY, debug); - Optional> exprType = TypeManager.getByClass(expr.getReturnType()); - assert exprType.isPresent(); - return StringUtils.withIndefiniteArticle(exprType.get().getBaseName(), !expr.isSingle()); - } } diff --git a/src/main/java/io/github/syst3ms/skriptparser/expressions/CondExprContains.java b/src/main/java/io/github/syst3ms/skriptparser/expressions/CondExprContains.java index 0d478fb5d..b8e1c06da 100644 --- a/src/main/java/io/github/syst3ms/skriptparser/expressions/CondExprContains.java +++ b/src/main/java/io/github/syst3ms/skriptparser/expressions/CondExprContains.java @@ -16,12 +16,12 @@ * See if a given list of objects contain a given element. * You can also check if a string contains another string. * + * @author Mwexim * @name Contain * @type CONDITION * @pattern %string% [does(n't| not)] contain[s] %string% * @pattern %objects% [do[es](n't| not)] contain[s] %objects% * @since ALPHA - * @author Mwexim */ public class CondExprContains extends ConditionalExpression { static { @@ -52,16 +52,16 @@ public boolean init(Expression[] expressions, int matchedPattern, ParseContex comparator = (Comparator) Comparators.getComparator(first.getReturnType(), second.getReturnType()).orElse(null); // If the expressions are variables, their return type is unknown at parse time if (first.getReturnType() != Object.class - && second.getReturnType() != Object.class - && comparator == null) { + && second.getReturnType() != Object.class + && comparator == null) { var logger = parseContext.getLogger(); logger.error( - "'" + + "'" + first.toString(TriggerContext.DUMMY, logger.isDebug()) + "' can never contain '" + second.toString(TriggerContext.DUMMY, logger.isDebug()) + "' because their values cannot be compared", - ErrorType.SEMANTIC_ERROR + ErrorType.SEMANTIC_ERROR ); return false; } @@ -70,9 +70,9 @@ public boolean init(Expression[] expressions, int matchedPattern, ParseContex setNegated(parseContext.getNumericMark() == 1); if (!onlyString && !first.isAndList()) { parseContext.getLogger().error( - "An or-list cannot contain any values", - ErrorType.SEMANTIC_ERROR, - "If you want to check if an or-list 'contains' a value, you should do an equality check instead." + "An or-list cannot contain any values", + ErrorType.SEMANTIC_ERROR, + "If you want to check if an or-list 'contains' a value, you should do an equality check instead." ); return false; } @@ -83,19 +83,19 @@ public boolean init(Expression[] expressions, int matchedPattern, ParseContex public boolean check(TriggerContext ctx) { if (onlyString) { return isNegated() != DoubleOptional.ofOptional(first.getSingle(ctx), second.getSingle(ctx)) - .map(toCheck -> (String) toCheck, toMatch -> (String) toMatch) - .mapToOptional(String::contains) - .orElse(false); + .map(toCheck -> (String) toCheck, toMatch -> (String) toMatch) + .mapToOptional(String::contains) + .orElse(false); } else { return second.check( - ctx, - toMatch -> Expression.check( - first.getValues(ctx), - toCheck -> (comparator == null ? Comparators.compare(toCheck, toMatch) : comparator.apply(toCheck, toMatch)).is(Relation.EQUAL), - false, - !first.isAndList() - ), - isNegated() + ctx, + toMatch -> Expression.check( + first.getValues(ctx), + toCheck -> (comparator == null ? Comparators.compare(toCheck, toMatch) : comparator.apply(toCheck, toMatch)).is(Relation.EQUAL), + false, + !first.isAndList() + ), + isNegated() ); } } diff --git a/src/main/java/io/github/syst3ms/skriptparser/expressions/CondExprIsEmpty.java b/src/main/java/io/github/syst3ms/skriptparser/expressions/CondExprIsEmpty.java index 4434b2acb..ceef4a6c6 100644 --- a/src/main/java/io/github/syst3ms/skriptparser/expressions/CondExprIsEmpty.java +++ b/src/main/java/io/github/syst3ms/skriptparser/expressions/CondExprIsEmpty.java @@ -12,11 +12,11 @@ * If you want a string list to be checked as a list instead of all separate strings, * you should use the 'list' modifier at the end. * + * @author Olyno * @name Is Empty * @pattern %objects% (is|are)[( not|n't)] empty * @pattern %strings% (is|are)[( not|n't)] [an] empty string[s] * @since ALPHA - * @author Olyno */ public class CondExprIsEmpty extends ConditionalExpression { static { @@ -28,6 +28,9 @@ public class CondExprIsEmpty extends ConditionalExpression { .examples("if {_list::*} is empty:", "if {_string} is not empty:") .since("1.0.0") + .setPriority(1) + // Higher priority than CondExprContains(0) + // This prevents trying to compare to an object named "empty" .register(); } @@ -49,8 +52,8 @@ public boolean check(TriggerContext ctx) { } else { var values = expression.getValues(ctx); return isNegated() != (values.length != 1 - ? values.length == 0 - : values[0] instanceof String && ((String) values[0]).isBlank()); + ? values.length == 0 + : values[0] instanceof String && ((String) values[0]).isBlank()); } } diff --git a/src/main/java/io/github/syst3ms/skriptparser/expressions/CondExprIsSet.java b/src/main/java/io/github/syst3ms/skriptparser/expressions/CondExprIsSet.java index 0c2e3f283..789725e31 100644 --- a/src/main/java/io/github/syst3ms/skriptparser/expressions/CondExprIsSet.java +++ b/src/main/java/io/github/syst3ms/skriptparser/expressions/CondExprIsSet.java @@ -7,11 +7,11 @@ /** * Check if a given expression is set (null on the Java side) or not. * + * @author Syst3ms * @name Is Set * @type CONDITION * @pattern %~objects% (is|are)[ not|n't] set * @since ALPHA - * @author Syst3ms */ public class CondExprIsSet extends PropertyConditional { static { diff --git a/src/main/java/io/github/syst3ms/skriptparser/expressions/CondExprMatch.java b/src/main/java/io/github/syst3ms/skriptparser/expressions/CondExprMatch.java index 1bd8d031d..1407da661 100644 --- a/src/main/java/io/github/syst3ms/skriptparser/expressions/CondExprMatch.java +++ b/src/main/java/io/github/syst3ms/skriptparser/expressions/CondExprMatch.java @@ -11,11 +11,11 @@ /** * Check if the given strings match a certain regex expression. * + * @author Mwexim * @name Match * @type CONDITION * @pattern %strings% [do[es](n't| not)] [part[ial]ly] match[es] %strings% * @since ALPHA - * @author Mwexim */ public class CondExprMatch extends ConditionalExpression { static { @@ -45,21 +45,21 @@ public boolean init(Expression[] expressions, int matchedPattern, ParseContex @Override public boolean check(TriggerContext ctx) { return matched.check( + ctx, + toMatch -> pattern.check( ctx, - toMatch -> pattern.check( - ctx, - pattern -> partly ? Pattern.compile(pattern).matcher(toMatch).find() : toMatch.matches(pattern) - ), - isNegated() + pattern -> partly ? Pattern.compile(pattern).matcher(toMatch).find() : toMatch.matches(pattern) + ), + isNegated() ); } @Override public String toString(TriggerContext ctx, boolean debug) { return matched.toString(ctx, debug) - + (isNegated() ? " does not" : "") - + (partly ? " partially" : "") - + (isNegated() ? " match " : " matches ") - + pattern.toString(ctx, debug); + + (isNegated() ? " does not" : "") + + (partly ? " partially" : "") + + (isNegated() ? " match " : " matches ") + + pattern.toString(ctx, debug); } } diff --git a/src/main/java/io/github/syst3ms/skriptparser/expressions/ExecExprListOperators.java b/src/main/java/io/github/syst3ms/skriptparser/expressions/ExecExprListOperators.java index bbd0576b8..86404bc08 100644 --- a/src/main/java/io/github/syst3ms/skriptparser/expressions/ExecExprListOperators.java +++ b/src/main/java/io/github/syst3ms/skriptparser/expressions/ExecExprListOperators.java @@ -16,8 +16,8 @@ * Basic list operators that return the following elements: *
    *
  • {@code pop}: the last element
  • - *
  • {@code shift/poll}: the first element
  • - *
  • {@code extract}: a specific (or just the first/last) element
  • + *
  • {@code shift/poll}: the getFirst element
  • + *
  • {@code extract}: a specific (or just the getFirst/last) element
  • *
  • {@code splice}: elements in a certain bound
  • *
* However, this syntax can also be used as an effect. If this is the case, instead of returning @@ -29,195 +29,195 @@ * when a negative step function is used, the list is reversed as well as the lower and upper bounds, * which means the lower bound must be higher than the upper bound. * + * @author Mwexim * @name List Operators * @type EFFECT/EXPRESSION - * @pattern extract [the] (last|first|%integer%(st|nd|rd|th)) element out [of] %objects% + * @pattern extract [the] (last|getFirst|%integer%(st|nd|rd|th)) element out [of] %objects% * @pattern pop %objects% - * @pattern (shift|poll) %objects% + * @pattern (shift | poll) %objects% * @pattern splice %objects% (from %integer% to %integer%|starting (at|from) %integer%|up to %integer%) [[with] step %integer%] - * @since ALPHA - * @author Mwexim * @see ExprElement + * @since ALPHA */ public class ExecExprListOperators extends ExecutableExpression { - static { - Parser.getMainRegistration().addExecutableExpression( - ExecExprListOperators.class, - Object.class, - false, - "extract [the] (0:last|1:first|2:%integer%(st|nd|rd|th)) element out [of] %objects%", - "pop %objects%", - "(shift|poll) %objects%", - "splice %objects% (0:from %integer% to %integer%|1:starting (at|from) %integer%|2:up to %integer%) [[with] step %integer%]" - ); - } + static { + Parser.getMainRegistration().addExecutableExpression( + ExecExprListOperators.class, + Object.class, + false, + "extract [the] (0:last|1:getFirst|2:%integer%(st|nd|rd|th)) element out [of] %objects%", + "pop %objects%", + "(shift|poll) %objects%", + "splice %objects% (0:from %integer% to %integer%|1:starting (at|from) %integer%|2:up to %integer%) [[with] step %integer%]" + ); + } - // 0 = last, 1 = first, 2 = indexed, 3 = spliced - private int type; - private Expression list; - private Expression index; - private Expression lower; - private Expression upper; - private Expression step; + // 0 = last, 1 = getFirst, 2 = indexed, 3 = spliced + private int type; + private Expression list; + private Expression index; + private Expression lower; + private Expression upper; + private Expression step; - @SuppressWarnings("unchecked") - @Override - public boolean init(Expression[] expressions, int matchedPattern, ParseContext parseContext) { - switch (matchedPattern) { - case 0: - type = parseContext.getNumericMark(); - list = (Expression) (type == 2 ? expressions[1] : expressions[0]); - if (type == 2) - index = (Expression) expressions[0]; - break; - case 1: - case 2: - type = matchedPattern - 1; - list = (Expression) expressions[0]; - break; - case 3: - type = 3; - list = (Expression) expressions[0]; - switch (parseContext.getNumericMark()) { - case 0: - lower = (Expression) expressions[1]; - upper = (Expression) expressions[2]; - if (expressions.length == 4) - step = (Expression) expressions[3]; - break; - case 1: - lower = (Expression) expressions[1]; - if (expressions.length == 3) - step = (Expression) expressions[2]; - break; - case 2: - upper = (Expression) expressions[1]; - if (expressions.length == 3) - step = (Expression) expressions[2]; - break; - default: - throw new IllegalStateException(); - } - } - var logger = parseContext.getLogger(); - if (!list.acceptsChange(ChangeMode.SET, list.getReturnType(), false)) { - logger.error( - list.toString(TriggerContext.DUMMY, logger.isDebug()) - + "' cannot be set to multiple values", - ErrorType.SEMANTIC_ERROR - ); - return false; - } else if (list.isSingle()) { - logger.error( - list.toString(TriggerContext.DUMMY, logger.isDebug()) + " represents a single value", - ErrorType.SEMANTIC_ERROR, - "List operators only work on multiple objects at the same time" - ); - return false; - } - return true; - } + @SuppressWarnings("unchecked") + @Override + public boolean init(Expression[] expressions, int matchedPattern, ParseContext parseContext) { + switch (matchedPattern) { + case 0: + type = parseContext.getNumericMark(); + list = (Expression) (type == 2 ? expressions[1] : expressions[0]); + if (type == 2) + index = (Expression) expressions[0]; + break; + case 1: + case 2: + type = matchedPattern - 1; + list = (Expression) expressions[0]; + break; + case 3: + type = 3; + list = (Expression) expressions[0]; + switch (parseContext.getNumericMark()) { + case 0: + lower = (Expression) expressions[1]; + upper = (Expression) expressions[2]; + if (expressions.length == 4) + step = (Expression) expressions[3]; + break; + case 1: + lower = (Expression) expressions[1]; + if (expressions.length == 3) + step = (Expression) expressions[2]; + break; + case 2: + upper = (Expression) expressions[1]; + if (expressions.length == 3) + step = (Expression) expressions[2]; + break; + default: + throw new IllegalStateException(); + } + } + var logger = parseContext.getLogger(); + if (!list.acceptsChange(ChangeMode.SET, list.getReturnType(), false)) { + logger.error( + list.toString(TriggerContext.DUMMY, logger.isDebug()) + + "' cannot be set to multiple values", + ErrorType.SEMANTIC_ERROR + ); + return false; + } else if (list.isSingle()) { + logger.error( + list.toString(TriggerContext.DUMMY, logger.isDebug()) + " represents a single value", + ErrorType.SEMANTIC_ERROR, + "List operators only work on multiple objects at the same time" + ); + return false; + } + return true; + } - @Override - public Object[] getValues(TriggerContext ctx, boolean isEffect) { - var values = list.getValues(ctx); - if (values.length == 0) - return new Object[0]; + @Override + public Object[] getValues(TriggerContext ctx, boolean isEffect) { + var values = list.getValues(ctx); + if (values.length == 0) + return new Object[0]; - switch (type) { - case 0: - if (isEffect) - list.change(ctx, ChangeMode.SET, Arrays.copyOfRange(values, 0, values.length - 1)); - return new Object[] {values[values.length - 1]}; - case 1: - if (isEffect) - list.change(ctx, ChangeMode.SET, Arrays.copyOfRange(values, 1, values.length)); - return new Object[] {values[0]}; - case 2: - int ind = index.getSingle(ctx) - .filter(n -> Integer.signum(n) > 0 && n.compareTo(Integer.valueOf(values.length)) <= 0) - .map(n -> n.intValue() - 1) - .orElse(-1); - if (ind == -1) { - return new Object[0]; - } + switch (type) { + case 0: + if (isEffect) + list.change(ctx, ChangeMode.SET, Arrays.copyOfRange(values, 0, values.length - 1)); + return new Object[]{values[values.length - 1]}; + case 1: + if (isEffect) + list.change(ctx, ChangeMode.SET, Arrays.copyOfRange(values, 1, values.length)); + return new Object[]{values[0]}; + case 2: + int ind = index.getSingle(ctx) + .filter(n -> Integer.signum(n) > 0 && n.compareTo(Integer.valueOf(values.length)) <= 0) + .map(n -> n.intValue() - 1) + .orElse(-1); + if (ind == -1) { + return new Object[0]; + } - // When used as an effect - if (isEffect) { - var skipped = new Object[values.length - 1]; - for (int i = 0, k = 0; i < values.length; i++) { - if (i == ind) { - continue; - } - skipped[k++] = values[i]; - } - list.change(ctx, ChangeMode.SET, skipped); - } - return new Object[] {values[ind]}; - case 3: - var low = lower != null - ? lower.getSingle(ctx).filter(n -> Integer.signum(n) > 0).map(n -> n.intValue() - 1).orElse(-1) - : 0; - var up = upper != null - ? upper.getSingle(ctx).filter(n -> n.compareTo(Integer.valueOf(values.length)) <= 0).map(Integer::intValue).orElse(values.length) - : values.length; - var st = step != null - ? step.getSingle(ctx).filter(n -> Integer.signum(n) != 0 && n.compareTo(Integer.valueOf(-values.length)) >= 0 && n.compareTo(Integer.valueOf(values.length)) <= 0).map(Integer::intValue).orElse(0) - : 1; + // When used as an effect + if (isEffect) { + var skipped = new Object[values.length - 1]; + for (int i = 0, k = 0; i < values.length; i++) { + if (i == ind) { + continue; + } + skipped[k++] = values[i]; + } + list.change(ctx, ChangeMode.SET, skipped); + } + return new Object[]{values[ind]}; + case 3: + var low = lower != null + ? lower.getSingle(ctx).filter(n -> Integer.signum(n) > 0).map(n -> n.intValue() - 1).orElse(-1) + : 0; + var up = upper != null + ? upper.getSingle(ctx).filter(n -> n.compareTo(Integer.valueOf(values.length)) <= 0).map(Integer::intValue).orElse(values.length) + : values.length; + var st = step != null + ? step.getSingle(ctx).filter(n -> Integer.signum(n) != 0 && n.compareTo(Integer.valueOf(-values.length)) >= 0 && n.compareTo(Integer.valueOf(values.length)) <= 0).map(Integer::intValue).orElse(0) + : 1; - if (st < 0) { - CollectionUtils.reverseArray(values); - st = -st; - int temp = low; - low = up - 1; - up = temp + 1; - } - if (low == -1 || up == -1 || up == 0 || st == 0 || low > up) { - if (isEffect) - list.change(ctx, ChangeMode.SET, new Object[0]); - return new Object[0]; - } else if (low == up) { - // Nothing to change - return new Object[0]; - } + if (st < 0) { + CollectionUtils.reverseArray(values); + st = -st; + int temp = low; + low = up - 1; + up = temp + 1; + } + if (low == -1 || up == -1 || up == 0 || st == 0 || low > up) { + if (isEffect) + list.change(ctx, ChangeMode.SET, new Object[0]); + return new Object[0]; + } else if (low == up) { + // Nothing to change + return new Object[0]; + } - var spliced = new ArrayList<>(); - var changed = new ArrayList<>(); - for (int i = 0; i < values.length; i++) { - if (i >= low && i < up && (i - low) % st == 0) { - spliced.add(values[i]); - } else { - changed.add(values[i]); - } - } + var spliced = new ArrayList<>(); + var changed = new ArrayList<>(); + for (int i = 0; i < values.length; i++) { + if (i >= low && i < up && (i - low) % st == 0) { + spliced.add(values[i]); + } else { + changed.add(values[i]); + } + } - if (isEffect) - list.change(ctx, ChangeMode.SET, changed.toArray()); - return spliced.toArray(new Object[0]); - default: - throw new IllegalStateException(); - } - } + if (isEffect) + list.change(ctx, ChangeMode.SET, changed.toArray()); + return spliced.toArray(new Object[0]); + default: + throw new IllegalStateException(); + } + } - @Override - public boolean isSingle() { - return type != 3; - } + @Override + public boolean isSingle() { + return type != 3; + } - @Override - public String toString(TriggerContext ctx, boolean debug) { - switch (type) { - case 0: - return "pop " + list.toString(ctx, debug); - case 1: - return "poll " + list.toString(ctx, debug); - case 2: - return "extract element number " + index.toString(ctx, debug) + " from " + list.toString(ctx, debug); - case 3: - return "splice " + list.toString(ctx, debug) + " from " + lower.toString(ctx, debug) - + (upper != null ? upper.toString(ctx, debug) : ""); - default: - throw new IllegalStateException(); - } - } + @Override + public String toString(TriggerContext ctx, boolean debug) { + switch (type) { + case 0: + return "pop " + list.toString(ctx, debug); + case 1: + return "poll " + list.toString(ctx, debug); + case 2: + return "extract element number " + index.toString(ctx, debug) + " from " + list.toString(ctx, debug); + case 3: + return "splice " + list.toString(ctx, debug) + " from " + lower.toString(ctx, debug) + + (upper != null ? upper.toString(ctx, debug) : ""); + default: + throw new IllegalStateException(); + } + } } diff --git a/src/main/java/io/github/syst3ms/skriptparser/expressions/ExecExprReplace.java b/src/main/java/io/github/syst3ms/skriptparser/expressions/ExecExprReplace.java index 438cbee19..1d7463c08 100644 --- a/src/main/java/io/github/syst3ms/skriptparser/expressions/ExecExprReplace.java +++ b/src/main/java/io/github/syst3ms/skriptparser/expressions/ExecExprReplace.java @@ -20,124 +20,124 @@ *
* Note that indices in Skript start at one. * + * @author Mwexim * @name Replace * @type EFFECT/EXPRESSION - * @pattern replace [(all|every|[the] first|[the] last)] [regex [pattern[s]]] %strings% in %strings% with %string% - * @pattern replace [(all|every|[the] first|[the] last)] [regex [pattern[s]]] %strings% with %string% in %strings% - * @since ALPHA - * @author Mwexim + * @pattern replace [(all|every|[the] getFirst|[the] last)] [regex [pattern[s]]] %strings% in %strings% with %string% + * @pattern replace [(all|every|[the] getFirst|[the] last)] [regex [pattern[s]]] %strings% with %string% in %strings% * @see ExprElement + * @since ALPHA */ public class ExecExprReplace extends ExecutableExpression { - static { - // TODO add "new" so we can add docs - Parser.getMainRegistration().addExecutableExpression(ExecExprReplace.class, String.class, false, - "replace [(0:all|0:every|1:[the] first|2:[the] last)] [:regex [pattern[s]]] %strings% in %strings% with %string%", - "replace [(0:all|0:every|1:[the] first|2:[the] last)] [:regex [pattern[s]]] %strings% with %string% in %strings%" - ); - } + static { + // TODO add "new" so we can add docs + Parser.getMainRegistration().addExecutableExpression(ExecExprReplace.class, String.class, false, + "replace [(0:all|0:every|1:[the] getFirst|2:[the] last)] [:regex [pattern[s]]] %strings% in %strings% with %string%", + "replace [(0:all|0:every|1:[the] getFirst|2:[the] last)] [:regex [pattern[s]]] %strings% with %string% in %strings%" + ); + } - private Expression toMatch; - private Expression toReplace; - private Expression replacement; + private Expression toMatch; + private Expression toReplace; + private Expression replacement; - private int type; - private boolean regex; + private int type; + private boolean regex; - @SuppressWarnings("unchecked") - @Override - public boolean init(Expression[] expressions, int matchedPattern, ParseContext parseContext) { - type = parseContext.getNumericMark(); - regex = parseContext.hasMark("regex"); + @SuppressWarnings("unchecked") + @Override + public boolean init(Expression[] expressions, int matchedPattern, ParseContext parseContext) { + type = parseContext.getNumericMark(); + regex = parseContext.hasMark("regex"); - toMatch = (Expression) expressions[0]; - toReplace = (Expression) expressions[1 + matchedPattern]; - replacement = (Expression) expressions[2 - matchedPattern]; + toMatch = (Expression) expressions[0]; + toReplace = (Expression) expressions[1 + matchedPattern]; + replacement = (Expression) expressions[2 - matchedPattern]; - if (!toReplace.acceptsChange(ChangeMode.SET, toReplace)) { - var logger = parseContext.getLogger(); - logger.error( - "The expression '" - + toReplace.toString(TriggerContext.DUMMY, logger.isDebug()) - + "' cannot be changed", - ErrorType.SEMANTIC_ERROR - ); - return false; - } - return true; - } + if (!toReplace.acceptsChange(ChangeMode.SET, toReplace)) { + var logger = parseContext.getLogger(); + logger.error( + "The expression '" + + toReplace.toString(TriggerContext.DUMMY, logger.isDebug()) + + "' cannot be changed", + ErrorType.SEMANTIC_ERROR + ); + return false; + } + return true; + } - @Override - public String[] getValues(TriggerContext ctx, boolean isEffect) { - String[] replacedValues = toReplace.getValues(ctx); - String[] matchedValues = toMatch.getValues(ctx); - String replacementValue = replacement.getSingle(ctx).orElse(null); - if (replacementValue == null) { - return replacedValues; - } + @Override + public String[] getValues(TriggerContext ctx, boolean isEffect) { + String[] replacedValues = toReplace.getValues(ctx); + String[] matchedValues = toMatch.getValues(ctx); + String replacementValue = replacement.getSingle(ctx).orElse(null); + if (replacementValue == null) { + return replacedValues; + } - for (int i = 0; i < replacedValues.length; i++) { - for (String match : matchedValues) { - String current = replacedValues[i]; - String replaced; - if (regex) { - // The regex pattern must be valid - try { - Pattern.compile(match); - } catch (PatternSyntaxException ignored) { - continue; - } - } - switch (type) { - case 0: - // All occurrences - replaced = regex - ? current.replaceAll(match, replacementValue) - : current.replace(match, replacementValue); - break; - case 1: - // First occurrence - replaced = current.replaceFirst( - regex ? match : Pattern.quote(match), - replacementValue - ); - break; - case 2: - // Last occurrence - // This regex pattern flushes away as many characters as it can, leaving the last occurrence. - Matcher matcher = Pattern.compile(".*(" + match + ")").matcher(current); - if (regex && !matcher.matches()) - continue; + for (int i = 0; i < replacedValues.length; i++) { + for (String match : matchedValues) { + String current = replacedValues[i]; + String replaced; + if (regex) { + // The regex pattern must be valid + try { + Pattern.compile(match); + } catch (PatternSyntaxException ignored) { + continue; + } + } + switch (type) { + case 0: + // All occurrences + replaced = regex + ? current.replaceAll(match, replacementValue) + : current.replace(match, replacementValue); + break; + case 1: + // First occurrence + replaced = current.replaceFirst( + regex ? match : Pattern.quote(match), + replacementValue + ); + break; + case 2: + // Last occurrence + // This regex pattern flushes away as many characters as it can, leaving the last occurrence. + Matcher matcher = Pattern.compile(".*(" + match + ")").matcher(current); + if (regex && !matcher.matches()) + continue; - int lastIndex = regex - ? matcher.start(1) - : current.lastIndexOf(match); - if (lastIndex < 0 || lastIndex >= current.length()) - continue; + int lastIndex = regex + ? matcher.start(1) + : current.lastIndexOf(match); + if (lastIndex < 0 || lastIndex >= current.length()) + continue; - int limitIndex = lastIndex + (regex - ? matcher.group(1).length() - : match.length()); - replaced = current.substring(0, lastIndex) - + replacementValue - + (limitIndex < current.length() ? current.substring(limitIndex) : ""); - break; - default: - throw new IllegalStateException(); - } - replacedValues[i] = replaced; - } - } - if (isEffect) - toReplace.change(ctx, ChangeMode.SET, replacedValues); - return replacedValues; - } + int limitIndex = lastIndex + (regex + ? matcher.group(1).length() + : match.length()); + replaced = current.substring(0, lastIndex) + + replacementValue + + (limitIndex < current.length() ? current.substring(limitIndex) : ""); + break; + default: + throw new IllegalStateException(); + } + replacedValues[i] = replaced; + } + } + if (isEffect) + toReplace.change(ctx, ChangeMode.SET, replacedValues); + return replacedValues; + } - @Override - public String toString(TriggerContext ctx, boolean debug) { - return "replace " - + new String[] {"all ", "first ", "last "}[type] + toMatch.toString(ctx, debug) - + " in " + toReplace.toString(ctx, debug) - + " with " + replacement.toString(ctx, debug); - } + @Override + public String toString(TriggerContext ctx, boolean debug) { + return "replace " + + new String[]{"all ", "getFirst ", "last "}[type] + toMatch.toString(ctx, debug) + + " in " + toReplace.toString(ctx, debug) + + " with " + replacement.toString(ctx, debug); + } } diff --git a/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprAmount.java b/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprAmount.java index 289b93f56..3710bd104 100644 --- a/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprAmount.java +++ b/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprAmount.java @@ -13,75 +13,75 @@ /** * The amount of elements in a given list. - * Note that when getting the size of a list variable, it will only return the size of the first layer of elements. + * Note that when getting the size of a list variable, it will only return the size of the getFirst layer of elements. * If you want to get the whole list size, including nested layers in a variable, use the recursive size instead. * + * @author Olyno, Mwexim * @name Amount * @type EXPRESSION * @pattern [the] [recursive] (amount|number|size) of %~objects% * @pattern %~objects%'[s] [recursive] (amount|number|size) * @since ALPHA - * @author Olyno, Mwexim */ public class ExprAmount extends PropertyExpression { - static { - Parser.getMainRegistration().newPropertyExpression(ExprAmount.class, Number.class, - "[1:recursive] (amount|number|size)", "~objects") - .name("Amount") - .description("Returns the amount of elements in a given list.") - .examples("set {_size} to size of {_var::*}", - "if size of all players > 10:") - .since("1.0.0") - .register(); - } + static { + Parser.getMainRegistration().newPropertyExpression(ExprAmount.class, Number.class, + "[1:recursive] (amount|number|size)", "~objects") + .name("Amount") + .description("Returns the amount of elements in a given list.") + .examples("set {_size} to size of {_var::*}", + "if size of all players > 10:") + .since("1.0.0") + .register(); + } - private boolean recursive; + private boolean recursive; - @Override - public boolean init(Expression @NotNull [] expressions, int matchedPattern, @NotNull ParseContext parseContext) { - super.init(expressions, matchedPattern, parseContext); - recursive = parseContext.getNumericMark() == 1; - if (recursive && !(getOwner() instanceof Variable)) { - parseContext.getLogger().error("Getting the recursive size of an expression only applies to variables.", ErrorType.SEMANTIC_ERROR); - return false; - } - return true; - } + @SuppressWarnings("unchecked") + private static long getRecursiveSize(Map map) { + long count = 0; + for (Map.Entry entry : map.entrySet()) { + Object value = entry.getValue(); + if (value instanceof Map) { + count += getRecursiveSize((Map) value); + } else { + count++; + } + } + return count; + } - @SuppressWarnings("unchecked") - @Override - public Number[] getValues(TriggerContext ctx) { - if (recursive) { - var var = ((Variable) getOwner()).getRaw(ctx); - if (var.isPresent()) - return new Number[] { - Integer.valueOf(Math.toIntExact(getRecursiveSize((Map) var.get()))) - }; - } - return new Number[] {Integer.valueOf(getOwner().getValues(ctx).length)}; - } + @Override + public boolean init(Expression @NotNull [] expressions, int matchedPattern, @NotNull ParseContext parseContext) { + super.init(expressions, matchedPattern, parseContext); + recursive = parseContext.getNumericMark() == 1; + if (recursive && !(getOwner() instanceof Variable)) { + parseContext.getLogger().error("Getting the recursive size of an expression only applies to variables.", ErrorType.SEMANTIC_ERROR); + return false; + } + return true; + } - @Override - public String toString(TriggerContext ctx, boolean debug) { - return toString(ctx, debug, (recursive ? "recursive " : "") + "size"); - } + @SuppressWarnings("unchecked") + @Override + public Number[] getValues(TriggerContext ctx) { + if (recursive) { + var var = ((Variable) getOwner()).getRaw(ctx); + if (var.isPresent()) + return new Number[]{ + Integer.valueOf(Math.toIntExact(getRecursiveSize((Map) var.get()))) + }; + } + return new Number[]{Integer.valueOf(getOwner().getValues(ctx).length)}; + } - @Override - public boolean isSingle() { - return true; - } + @Override + public String toString(TriggerContext ctx, boolean debug) { + return toString(ctx, debug, (recursive ? "recursive " : "") + "size"); + } - @SuppressWarnings("unchecked") - private static long getRecursiveSize(Map map) { - long count = 0; - for (Map.Entry entry : map.entrySet()) { - Object value = entry.getValue(); - if (value instanceof Map) { - count += getRecursiveSize((Map) value); - } else { - count++; - } - } - return count; - } + @Override + public boolean isSingle() { + return true; + } } diff --git a/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprAnswer.java b/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprAnswer.java index 55a2cd5c9..317148111 100644 --- a/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprAnswer.java +++ b/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprAnswer.java @@ -12,14 +12,16 @@ * Retrieve the last input of the user in a {@link EffAsk} effect. * This will essentially return the last line of the console. * + * @author ItsTheSky * @name Last Answer * @type EXPRESSION * @pattern [the] [last] (answer|response) * @since ALPHA - * @author ItsTheSky */ public class ExprAnswer implements Expression { + private static final Map answers = new HashMap<>(); + static { // We won't be needing this // Parser.getMainRegistration().addExpression( @@ -30,8 +32,6 @@ public class ExprAnswer implements Expression { // ); } - private static final Map answers = new HashMap<>(); - public static void addAnswer(TriggerContext ctx, String answer) { answers.put(ctx, answer); } @@ -44,8 +44,8 @@ public boolean init(Expression[] expressions, int matchedPattern, ParseContex @Override public String[] getValues(TriggerContext ctx) { return answers.containsKey(ctx) - ? new String[] {answers.get(ctx)} - : new String[0]; + ? new String[]{answers.get(ctx)} + : new String[0]; } @Override diff --git a/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprBooleanOperators.java b/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprBooleanOperators.java index 67e42c07f..b616312f8 100644 --- a/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprBooleanOperators.java +++ b/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprBooleanOperators.java @@ -11,17 +11,17 @@ /** * Basic boolean operators. It is possible to use conditions inside the operators. * + * @author Syst3ms * @name Boolean Operators * @pattern not %=boolean% * @pattern %=boolean% (or|\|\|) %=boolean% * @pattern %=boolean% (and|&&) %=boolean% * @since ALPHA - * @author Syst3ms */ public class ExprBooleanOperators implements Expression { static { Parser.getMainRegistration().newExpression( - ExprBooleanOperators.class, Boolean.class, true, + ExprBooleanOperators.class, Boolean.class, true, "not %=boolean%", "%=boolean% (or|\\|\\|) %=boolean%", "%=boolean% (and|&&) %=boolean%") @@ -54,12 +54,12 @@ public boolean init(Expression[] expressions, int matchedPattern, ParseContex public Boolean[] getValues(TriggerContext ctx) { assert second != null || pattern == 0; return first.getSingle(ctx) - .flatMap(f -> pattern == 0 - ? Optional.of(!f) - : second.getSingle(ctx).map(s -> pattern == 1 ? f || s : f && s) - ) - .map(val -> new Boolean[] {val}) - .orElse(new Boolean[0]); + .flatMap(f -> pattern == 0 + ? Optional.of(!f) + : second.getSingle(ctx).map(s -> pattern == 1 ? f || s : f && s) + ) + .map(val -> new Boolean[]{val}) + .orElse(new Boolean[0]); } @Override diff --git a/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprColorFromHex.java b/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprColorFromHex.java index 90a38db10..c471898be 100644 --- a/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprColorFromHex.java +++ b/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprColorFromHex.java @@ -15,41 +15,41 @@ * * A trailing hashtag (#) at the start of the string is allowed, but not necessary. * + * @author Mwexim * @name Color from Hex * @type EXPRESSION * @pattern [the] color (from|of) [the] hex[adecimal] [value] %string% * @since ALPHA - * @author Mwexim */ public class ExprColorFromHex implements Expression { - static { - Parser.getMainRegistration().newExpression(ExprColorFromHex.class, Color.class, true, - "[the] color (from|of) [the] hex[adecimal] [value] %string%") - .name("Color from Hex") - .description("Creates a color from its hexadecimal value.") - .since("1.0.0") - .register(); - } + static { + Parser.getMainRegistration().newExpression(ExprColorFromHex.class, Color.class, true, + "[the] color (from|of) [the] hex[adecimal] [value] %string%") + .name("Color from Hex") + .description("Creates a color from its hexadecimal value.") + .since("1.0.0") + .register(); + } - private Expression hex; + private Expression hex; - @SuppressWarnings("unchecked") - @Override - public boolean init(Expression[] expressions, int matchedPattern, ParseContext parseContext) { - hex = (Expression) expressions[0]; - return true; - } + @SuppressWarnings("unchecked") + @Override + public boolean init(Expression[] expressions, int matchedPattern, ParseContext parseContext) { + hex = (Expression) expressions[0]; + return true; + } - @Override - public Color[] getValues(TriggerContext ctx) { - return hex.getSingle(ctx) - .flatMap(val -> Color.ofHex(val.startsWith("#") ? val.substring(1) : val)) - .map(val -> new Color[] {val}) - .orElse(new Color[0]); - } + @Override + public Color[] getValues(TriggerContext ctx) { + return hex.getSingle(ctx) + .flatMap(val -> Color.ofHex(val.startsWith("#") ? val.substring(1) : val)) + .map(val -> new Color[]{val}) + .orElse(new Color[0]); + } - @Override - public String toString(TriggerContext ctx, boolean debug) { - return "color from hex " + hex.toString(ctx, debug); - } + @Override + public String toString(TriggerContext ctx, boolean debug) { + return "color from hex " + hex.toString(ctx, debug); + } } diff --git a/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprColorFromRGB.java b/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprColorFromRGB.java index 3b225411b..e17dee451 100644 --- a/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprColorFromRGB.java +++ b/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprColorFromRGB.java @@ -13,49 +13,49 @@ * It is also possible to add the alpha value, which corresponds to the transparency. * If the argument size is not exactly 3 or 4, no color will be created. * + * @author Mwexim * @name Color from RGB * @type EXPRESSION * @pattern [the] color (from|of) [the] rgb[a] [value] %integers% * @since ALPHA - * @author Mwexim */ public class ExprColorFromRGB implements Expression { - static { - Parser.getMainRegistration().newExpression(ExprColorFromRGB.class, Color.class, true, - "[the] color (from|of) [the] rgb[a] [value] %integers%") - .name("Color from RGB") - .description("Creates a color from its RGB values.") - .since("1.0.0") - .register(); - } + static { + Parser.getMainRegistration().newExpression(ExprColorFromRGB.class, Color.class, true, + "[the] color (from|of) [the] rgb[a] [value] %integers%") + .name("Color from RGB") + .description("Creates a color from its RGB values.") + .since("1.0.0") + .register(); + } - private Expression rgb; + private Expression rgb; - @SuppressWarnings("unchecked") - @Override - public boolean init(Expression[] expressions, int matchedPattern, ParseContext parseContext) { - rgb = (Expression) expressions[0]; - return true; - } + @SuppressWarnings("unchecked") + @Override + public boolean init(Expression[] expressions, int matchedPattern, ParseContext parseContext) { + rgb = (Expression) expressions[0]; + return true; + } - @Override - public Color[] getValues(TriggerContext ctx) { - var values = rgb.stream(ctx).map(Integer::intValue).toArray(Integer[]::new); - if (values.length == 3) { - return Color.of(values[0], values[1], values[2]) - .map(val -> new Color[] {val}) - .orElse(new Color[0]); - } else if (values.length == 4) { - return Color.of(values[0], values[1], values[2], values[3]) - .map(val -> new Color[] {val}) - .orElse(new Color[0]); - } else { - return new Color[0]; - } - } + @Override + public Color[] getValues(TriggerContext ctx) { + var values = rgb.stream(ctx).map(Integer::intValue).toArray(Integer[]::new); + if (values.length == 3) { + return Color.of(values[0], values[1], values[2]) + .map(val -> new Color[]{val}) + .orElse(new Color[0]); + } else if (values.length == 4) { + return Color.of(values[0], values[1], values[2], values[3]) + .map(val -> new Color[]{val}) + .orElse(new Color[0]); + } else { + return new Color[0]; + } + } - @Override - public String toString(TriggerContext ctx, boolean debug) { - return "color from rgb " + rgb.toString(ctx, debug); - } + @Override + public String toString(TriggerContext ctx, boolean debug) { + return "color from rgb " + rgb.toString(ctx, debug); + } } diff --git a/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprContextValue.java b/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprContextValue.java new file mode 100644 index 000000000..d20f5d75c --- /dev/null +++ b/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprContextValue.java @@ -0,0 +1,157 @@ +package io.github.syst3ms.skriptparser.expressions; + +import io.github.syst3ms.skriptparser.Parser; +import io.github.syst3ms.skriptparser.lang.Expression; +import io.github.syst3ms.skriptparser.lang.TriggerContext; +import io.github.syst3ms.skriptparser.log.ErrorContext; +import io.github.syst3ms.skriptparser.log.ErrorType; +import io.github.syst3ms.skriptparser.log.SkriptLogger; +import io.github.syst3ms.skriptparser.parsing.MatchContext; +import io.github.syst3ms.skriptparser.parsing.ParseContext; +import io.github.syst3ms.skriptparser.parsing.ParserState; +import io.github.syst3ms.skriptparser.pattern.PatternElement; +import io.github.syst3ms.skriptparser.pattern.PatternParser; +import io.github.syst3ms.skriptparser.registration.context.ContextValue; +import io.github.syst3ms.skriptparser.registration.context.ContextValue.State; +import io.github.syst3ms.skriptparser.registration.context.ContextValues; +import io.github.syst3ms.skriptparser.types.changers.ChangeMode; +import org.jetbrains.annotations.Contract; + +import java.lang.reflect.Array; +import java.util.Optional; + +public class ExprContextValue implements Expression { + + private static final String PATTERN = "[the] [(1:(past|previous)|2:(future|next))] [ctx:(context|event)-]<.+>"; + private static final PatternElement CONTEXT_VALUE_PATTERN = PatternParser.parsePattern(PATTERN, new SkriptLogger()).orElseThrow(); + + static { + //noinspection unchecked + Parser.getMainRegistration().newExpression(ExprContextValue.class, Object.class, false, + PATTERN) + .name("Context/Event Value") + .description("Returns a value from the current context/event.") + .examples("set {_var} to context-player") + .since("1.0.0") + .register(); + } + + private ContextValue info; + private String value; + private boolean alone; + + @SuppressWarnings("unchecked") + @Override + @Contract("_, _, _ -> fail") + public boolean init(Expression[] expressions, int matchedPattern, ParseContext parseContext) { + boolean alone = !parseContext.hasMark("ctx"); + String toParse = parseContext.getMatches().getFirst().group(); + String value = parseContext.getMatches().getFirst().group(); + State state = switch (parseContext.getNumericMark()) { + case 0 -> State.PRESENT; + case 1 -> State.PAST; + case 2 -> State.FUTURE; + default -> throw new IllegalArgumentException("Invalid state index: " + parseContext.getNumericMark()); + }; + + + ParserState parserState = parseContext.getParserState(); + SkriptLogger logger = parseContext.getLogger(); + + var matchContext = new MatchContext(CONTEXT_VALUE_PATTERN, parserState, logger); + + for (Class ctx : parserState.getCurrentContexts()) { + for (var info : ContextValues.getContextValues(ctx)) { + matchContext = new MatchContext(info.getPattern(), parserState, logger); + + // Checking all conditions, so no false results slip through. + if (info.getPattern().match(value, 0, matchContext) != value.length()) { + continue; + } else if (!info.getUsage().isCorrect(alone)) { + if (alone) { + logger.error( + "The context value matching '" + toParse + "' cannot be used alone", + ErrorType.SEMANTIC_ERROR, + "Use 'context-" + toParse + "' instead of using just '" + toParse + "' alone" + ); + } else { + logger.error( + "The context value matching '" + toParse + "' must be used alone", + ErrorType.SEMANTIC_ERROR, + "Instead of 'context-" + toParse + "', use this context value as '" + toParse + "'" + ); + } + return false; + } else if (state != info.getState()) { + logger.error("The time state of this context value (" + state.toString().toLowerCase() + ") is incorrect", ErrorType.SEMANTIC_ERROR); + return false; + } else if (parserState.isRestrictingExpressions() && parserState.forbidsSyntax(ExprContextValue.class)) { + logger.setContext(ErrorContext.RESTRICTED_SYNTAXES); + logger.error("The enclosing section does not allow the use of context expressions.", ErrorType.SEMANTIC_ERROR); + return false; + } + + this.info = (ContextValue) info; + this.value = value; + this.alone = alone; + return true; + } + } + if (!alone) { + logger.error("No context value matching '" + toParse + "' was found", ErrorType.SEMANTIC_ERROR); + } + return false; + } + + @SuppressWarnings("unchecked") + @Override + public T[] getValues(TriggerContext ctx) { + if (!this.info.getContext().isAssignableFrom(ctx.getClass())) { + return (T[]) Array.newInstance(getReturnType(), 0); + } + assert this.info.getContext().isInstance(ctx); + if (this.info.isSingle()) { + T apply = this.info.getSingleFunction().apply((C) ctx); + T[] array = (T[]) Array.newInstance(getReturnType(), 1); + array[0] = apply; + return array; + } else { + return this.info.getListFunction().apply((C) ctx); + } + } + + @Override + public Optional[]> acceptsChange(ChangeMode mode) { + if (mode == ChangeMode.SET && this.info.canBeSet()) return Optional.of(new Class[]{getReturnType()}); + return Optional.empty(); + } + + @SuppressWarnings("unchecked") + @Override + public void change(TriggerContext ctx, ChangeMode changeMode, Object[] changeWith) { + if (changeMode != ChangeMode.SET) return; + + if (this.info.isSingle()) { + this.info.getSingleSetterFunction().accept((C) ctx, (T) changeWith[0]); + } else { + this.info.getListSetterFunction().accept((C) ctx, (T[]) changeWith); + } + } + + @Override + public boolean isSingle() { + return this.info.isSingle(); + } + + @Override + public Class getReturnType() { + return this.info.getReturnType().getType().getTypeClass(); + } + + @Override + public String toString(TriggerContext ctx, boolean debug) { + return new String[]{"past ", "", "future "}[this.info.getState().ordinal()] + + (this.alone ? "" : "context-") + this.value; + } + +} diff --git a/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprDateAgoLater.java b/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprDateAgoLater.java index 3332c0f33..0ccd80f76 100644 --- a/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprDateAgoLater.java +++ b/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprDateAgoLater.java @@ -14,54 +14,54 @@ /** * The date that was a certain duration ago or is a certain duration in the future. * + * @author Mwexim * @name Ago/Later * @type EXPRESSION * @pattern %duration% (ago|in the past|before [the] [date] %date%) * @pattern %duration% (later|in the future|(from|after) [the] [date] %date%) * @since ALPHA - * @author Mwexim */ public class ExprDateAgoLater implements Expression { - static { - Parser.getMainRegistration().newExpression( - ExprDateAgoLater.class, - SkriptDate.class, - true, - "%duration% (ago|in the past|before [the] [date] %date%)", - "%duration% (later|in the future|(from|after) [the] [date] %date%)") - .name("Date Ago/Later") - .description("Returns the date that is a certain duration ago or in the future.") - .since("1.0.0") - .register(); - } + static { + Parser.getMainRegistration().newExpression( + ExprDateAgoLater.class, + SkriptDate.class, + true, + "%duration% (ago|in the past|before [the] [date] %date%)", + "%duration% (later|in the future|(from|after) [the] [date] %date%)") + .name("Date Ago/Later") + .description("Returns the date that is a certain duration ago or in the future.") + .since("1.0.0") + .register(); + } - private Expression duration; - @Nullable - private Expression date; - private boolean past; + private Expression duration; + @Nullable + private Expression date; + private boolean past; - @SuppressWarnings("unchecked") - @Override - public boolean init(Expression[] expressions, int matchedPattern, ParseContext parseContext) { - past = matchedPattern == 0; - duration = (Expression) expressions[0]; - if (expressions.length == 2) - date = (Expression) expressions[1]; - return true; - } + @SuppressWarnings("unchecked") + @Override + public boolean init(Expression[] expressions, int matchedPattern, ParseContext parseContext) { + past = matchedPattern == 0; + duration = (Expression) expressions[0]; + if (expressions.length == 2) + date = (Expression) expressions[1]; + return true; + } - @Override - public SkriptDate[] getValues(TriggerContext ctx) { - var actualDate = date != null ? date.getSingle(ctx) : Optional.of(SkriptDate.now()); - return DoubleOptional.ofOptional(actualDate, duration.getSingle(ctx)) - .mapToOptional((da, du) -> new SkriptDate[] {past ? da.minus(du) : da.plus(du)}) - .orElse(new SkriptDate[0]); - } + @Override + public SkriptDate[] getValues(TriggerContext ctx) { + var actualDate = date != null ? date.getSingle(ctx) : Optional.of(SkriptDate.now()); + return DoubleOptional.ofOptional(actualDate, duration.getSingle(ctx)) + .mapToOptional((da, du) -> new SkriptDate[]{past ? da.minus(du) : da.plus(du)}) + .orElse(new SkriptDate[0]); + } - @Override - public String toString(TriggerContext ctx, boolean debug) { - return date != null - ? duration.toString(ctx, debug) + (past ? " before date " : " after date ") + date.toString(ctx, debug) - : duration.toString(ctx, debug) + (past ? " in the past" : " in the future"); - } + @Override + public String toString(TriggerContext ctx, boolean debug) { + return date != null + ? duration.toString(ctx, debug) + (past ? " before date " : " after date ") + date.toString(ctx, debug) + : duration.toString(ctx, debug) + (past ? " in the past" : " in the future"); + } } diff --git a/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprDateInformation.java b/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprDateInformation.java index d940e435e..ff8f362da 100644 --- a/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprDateInformation.java +++ b/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprDateInformation.java @@ -19,7 +19,7 @@ * @author Mwexim * @name Date Information * @type EXPRESSION - * @pattern [the] (year[s]|month[s]|day[s] (of|in) year|day[s] (of|in) month|day[s] (of|in) week|hour[s]|minute[s]|second[s]|milli[second][s]) (of|in) %date/time% + * @pattern [the] (year[s]|month[s]|day[s] (of|in) year|day[s] (of|in) month|day[s] (of|in) week|hour[s]|minute[s]|getSecond[s]|milli[getSecond][s]) (of|in) %date/time% * @pattern [the] (era|month|weekday|day [(of|in) week]) [name] (of|in) [date] %date% * @since ALPHA */ @@ -32,8 +32,8 @@ public class ExprDateInformation implements Expression { {"day[s] (of|in) week", (Function) val -> val.getDayOfWeek().getValue()}, {"hour[s]", (Function) LocalDateTime::getHour}, {"minute[s]", (Function) LocalDateTime::getMinute}, - {"second[s]", (Function) LocalDateTime::getSecond}, - {"milli[second][s]", (Function) val -> val.getNano() / 1_000_000} + {"getSecond[s]", (Function) LocalDateTime::getSecond}, + {"milli[getSecond][s]", (Function) val -> val.getNano() / 1_000_000} }); private static final PatternInfos> STRING_VALUES = new PatternInfos<>(new Object[][]{ diff --git a/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprDateNow.java b/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprDateNow.java index ecef53faa..e6b47a955 100644 --- a/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprDateNow.java +++ b/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprDateNow.java @@ -11,11 +11,11 @@ /** * The current date, the one from yesterday or the one from tomorrow. * + * @author Mwexim * @name Now * @type EXPRESSION - * @pattern (yesterday|now|tomorrow) + * @pattern (yesterday | now | tomorrow) * @since ALPHA - * @author Mwexim */ public class ExprDateNow implements Expression { static { @@ -30,30 +30,30 @@ public class ExprDateNow implements Expression { .register(); } - private int mark; + private int mark; - @Override - public boolean init(Expression[] expressions, int matchedPattern, ParseContext parseContext) { - mark = parseContext.getNumericMark(); - return true; - } + @Override + public boolean init(Expression[] expressions, int matchedPattern, ParseContext parseContext) { + mark = parseContext.getNumericMark(); + return true; + } - @Override - public SkriptDate[] getValues(TriggerContext ctx) { - switch (mark) { - case 0: - return new SkriptDate[] {SkriptDate.now().minus(Duration.ofDays(1))}; - case 1: - return new SkriptDate[] {SkriptDate.now()}; - case 2: - return new SkriptDate[] {SkriptDate.now().plus(Duration.ofDays(1))}; - default: - throw new IllegalStateException(); - } - } + @Override + public SkriptDate[] getValues(TriggerContext ctx) { + switch (mark) { + case 0: + return new SkriptDate[]{SkriptDate.now().minus(Duration.ofDays(1))}; + case 1: + return new SkriptDate[]{SkriptDate.now()}; + case 2: + return new SkriptDate[]{SkriptDate.now().plus(Duration.ofDays(1))}; + default: + throw new IllegalStateException(); + } + } - @Override - public String toString(TriggerContext ctx, boolean debug) { - return new String[] {"yesterday", "now", "tomorrow"}[mark]; - } + @Override + public String toString(TriggerContext ctx, boolean debug) { + return new String[]{"yesterday", "now", "tomorrow"}[mark]; + } } diff --git a/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprDateTodayAt.java b/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprDateTodayAt.java index 922055767..d7312526c 100644 --- a/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprDateTodayAt.java +++ b/src/main/java/io/github/syst3ms/skriptparser/expressions/ExprDateTodayAt.java @@ -13,45 +13,46 @@ /** * Today at a given time. When no time is set, * it will take today's date as it would be midnight. + *

+ * + * @author Mwexim * -+ * @author Mwexim - * @name Today At - * @type EXPRESSION - * @pattern today [at %time%] - * @since ALPHA - */ + * @name Today At + * @type EXPRESSION + * @pattern today [at %time%] + * @since ALPHA + */ public class ExprDateTodayAt implements Expression { - static { - Parser.getMainRegistration().newExpression(ExprDateTodayAt.class, SkriptDate.class, true, - "today [at %time%]") - .name("Today At") - .description("Returns the date of today at a given time. If no time is specified, it will return the date of today at midnight.") - .since("1.0.0") - .register(); - } + static { + Parser.getMainRegistration().newExpression(ExprDateTodayAt.class, SkriptDate.class, true, + "today [at %time%]") + .name("Today At") + .description("Returns the date of today at a given time. If no time is specified, it will return the date of today at midnight.") + .since("1.0.0") + .register(); + } - @Nullable - private Expression