From ce79b118aa23dbbb14bd5a8cdb172f2e6b310113 Mon Sep 17 00:00:00 2001 From: _tud <98935832+UnderscoreTud@users.noreply.github.com> Date: Thu, 5 Sep 2024 02:15:53 +0300 Subject: [PATCH] Add simple helper methods for getting relative sections --- .../ch/njol/skript/effects/EffContinue.java | 61 ++++-------- .../java/ch/njol/skript/effects/EffExit.java | 98 ++++++++----------- .../ch/njol/skript/effects/EffReturn.java | 23 +++-- .../java/ch/njol/skript/lang/Section.java | 40 ++++++++ 4 files changed, 114 insertions(+), 108 deletions(-) diff --git a/src/main/java/ch/njol/skript/effects/EffContinue.java b/src/main/java/ch/njol/skript/effects/EffContinue.java index 04a3c7b0c4b..1684a17ea53 100644 --- a/src/main/java/ch/njol/skript/effects/EffContinue.java +++ b/src/main/java/ch/njol/skript/effects/EffContinue.java @@ -31,7 +31,6 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.UnknownNullability; -import java.util.ArrayList; import java.util.List; @Name("Continue") @@ -63,56 +62,36 @@ public class EffContinue extends Effect { ); } + // Used for toString + private int level; + private @UnknownNullability LoopSection loop; - private @UnknownNullability List innerLoops; - private int breakLevels; + private @UnknownNullability List innerSections; @Override @SuppressWarnings("unchecked") public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { - List sections = getParser().getCurrentSections(); - innerLoops = new ArrayList<>(); - int loopLevels = 0; - LoopSection lastLoop = null; - - int level = matchedPattern == 0 ? -1 : ((Literal) exprs[0]).getSingle(); + level = matchedPattern == 0 ? -1 : ((Literal) exprs[0]).getSingle(); if (matchedPattern != 0 && level < 1) { Skript.error("Can't continue the " + StringUtils.fancyOrderNumber(level) + " loop"); return false; } - for (TriggerSection section : sections) { - if (loop != null) - breakLevels++; - if (!(section instanceof LoopSection loopSection)) - continue; - loopLevels++; - if (level == -1) { - lastLoop = loopSection; - } else if (loopLevels == level) { - loop = loopSection; - breakLevels++; - } else if (loopLevels > level) { - innerLoops.add(loopSection); - } - } - - if (loopLevels == 0) { + int loops = getParser().getCurrentSections(LoopSection.class).size(); + if (loops == 0) { Skript.error("The 'continue' effect may only be used in loops"); return false; } - if (level > loopLevels) { + int levels = level == -1 ? 1 : loops - level + 1; + if (levels <= 0) { Skript.error("Can't continue the " + StringUtils.fancyOrderNumber(level) + " loop as there " + - (loopLevels == 1 ? "is only 1 loop" : "are only " + loopLevels + " loops") + " present"); + (loops == 1 ? "is only 1 loop" : "are only " + loops + " loops") + " present"); return false; } - if (level == -1) { - loop = lastLoop; - breakLevels++; - } - + innerSections = Section.getSections(levels, LoopSection.class); + loop = (LoopSection) innerSections.remove(0); return true; } @@ -122,21 +101,23 @@ protected void execute(Event event) { } @Override - @Nullable - protected TriggerItem walk(Event event) { - for (LoopSection loop : innerLoops) - loop.exit(event); + protected @Nullable TriggerItem walk(Event event) { + debug(event, false); + for (TriggerSection section : innerSections) { + if (section instanceof SectionExitHandler exitHandler) + exitHandler.exit(event); + } return loop; } @Override - public @Nullable ExecutionIntent executionIntent() { - return ExecutionIntent.stopSections(breakLevels); + public ExecutionIntent executionIntent() { + return ExecutionIntent.stopSections(innerSections.size() + 1); } @Override public String toString(@Nullable Event event, boolean debug) { - return "continue" + (loop == null ? "" : " the " + StringUtils.fancyOrderNumber(innerLoops.size() + 1) + " loop"); + return "continue" + (level == -1 ? "" : " the " + StringUtils.fancyOrderNumber(level) + " loop"); } } diff --git a/src/main/java/ch/njol/skript/effects/EffExit.java b/src/main/java/ch/njol/skript/effects/EffExit.java index 717bd13f526..74ee21ee521 100644 --- a/src/main/java/ch/njol/skript/effects/EffExit.java +++ b/src/main/java/ch/njol/skript/effects/EffExit.java @@ -25,12 +25,11 @@ import ch.njol.skript.doc.Since; import ch.njol.skript.lang.*; import ch.njol.skript.lang.SkriptParser.ParseResult; -import ch.njol.skript.lang.parser.ParserInstance; -import ch.njol.skript.log.ErrorQuality; import ch.njol.skript.sections.SecConditional; import ch.njol.util.Kleenean; import org.bukkit.event.Event; import org.eclipse.jdt.annotation.Nullable; +import org.jetbrains.annotations.UnknownNullability; import java.util.List; @@ -38,93 +37,80 @@ @Description("Exits a given amount of loops and conditionals, or the entire trigger.") @Examples({ "if player has any ore:", - "\tstop", + "\tstop", "message \"%player% has no ores!\"", "loop blocks above the player:", - "\tloop-block is not air:", - "\t\texit 2 sections", - "\tset loop-block to water" + "\tloop-block is not air:", + "\t\texit 2 sections", + "\tset loop-block to water" }) @Since("unknown (before 2.1)") public class EffExit extends Effect { static { Skript.registerEffect(EffExit.class, - "(exit|stop) [trigger]", - "(exit|stop) [(1|a|the|this)] (section|1:loop|2:conditional)", - "(exit|stop) <\\d+> (section|1:loop|2:conditional)s", - "(exit|stop) all (section|1:loop|2:conditional)s"); + "(exit|stop) [trigger]", + "(exit|stop) [(1|a|the|this)] (section|1:loop|2:conditional)", + "(exit|stop) <\\d+> (section|1:loop|2:conditional)s", + "(exit|stop) all (section|1:loop|2:conditional)s"); } - private int breakLevels; - - private static final int EVERYTHING = 0; - private static final int LOOPS = 1; - private static final int CONDITIONALS = 2; + @SuppressWarnings("unchecked") + private static final Class[] types = new Class[]{TriggerSection.class, LoopSection.class, SecConditional.class}; private static final String[] names = {"sections", "loops", "conditionals"}; private int type; + private int breakLevels; + private @UnknownNullability List sectionsToExit; + @Override public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parser) { switch (matchedPattern) { - case 0: - breakLevels = getParser().getCurrentSections().size() + 1; - type = EVERYTHING; - break; - case 1: - case 2: + case 0 -> { + sectionsToExit = getParser().getCurrentSections(); + breakLevels = sectionsToExit.size() + 1; + } + case 1, 2 -> { breakLevels = matchedPattern == 1 ? 1 : Integer.parseInt(parser.regexes.get(0).group()); type = parser.mark; - if (breakLevels > numLevels(type)) { - if (numLevels(type) == 0) - Skript.error("can't stop any " + names[type] + " as there are no " + names[type] + " present", ErrorQuality.SEMANTIC_ERROR); - else - Skript.error("can't stop " + breakLevels + " " + names[type] + " as there are only " + numLevels(type) + " " + names[type] + " present", ErrorQuality.SEMANTIC_ERROR); + sectionsToExit = Section.getSections(breakLevels, types[type]); + int levels = getParser().getCurrentSections(types[type]).size(); + if (breakLevels > levels) { + if (levels == 0) { + Skript.error("can't stop any " + names[type] + " as there are no " + names[type] + " present"); + } else { + Skript.error("can't stop " + breakLevels + " " + names[type] + " as there are only " + levels + " " + names[type] + " present"); + } return false; } - break; - case 3: + } + case 3 -> { type = parser.mark; - breakLevels = numLevels(type); - if (breakLevels == 0) { - Skript.error("can't stop any " + names[type] + " as there are no " + names[type] + " present", ErrorQuality.SEMANTIC_ERROR); + List sections = getParser().getCurrentSections(types[type]); + breakLevels = sections.size(); + if (sections.isEmpty()) { + Skript.error("can't stop any " + names[type] + " as there are no " + names[type] + " present"); return false; } - break; + TriggerSection firstSection = sections.get(0); + sectionsToExit = Section.getSectionsUntil(firstSection); + sectionsToExit.add(0, firstSection); + } } return true; } - private static int numLevels(int type) { - List currentSections = ParserInstance.get().getCurrentSections(); - if (type == EVERYTHING) - return currentSections.size(); - int level = 0; - for (TriggerSection section : currentSections) { - if (type == CONDITIONALS ? section instanceof SecConditional : section instanceof LoopSection) - level++; - } - return level; - } - @Override @Nullable protected TriggerItem walk(Event event) { debug(event, false); - TriggerItem node = this; - for (int i = breakLevels; i > 0;) { - node = node.getParent(); - if (node == null) { - assert false : this; - return null; - } - if (node instanceof SectionExitHandler exitHandler) + for (TriggerSection section : sectionsToExit) { + if (section instanceof SectionExitHandler exitHandler) exitHandler.exit(event); - - if (type == EVERYTHING || type == CONDITIONALS && node instanceof SecConditional || type == LOOPS && (node instanceof LoopSection)) - i--; } - return node instanceof LoopSection ? node.getActualNext() : node.getNext(); + if (breakLevels > sectionsToExit.size()) + return null; + return sectionsToExit.get(0).getActualNext(); } @Override diff --git a/src/main/java/ch/njol/skript/effects/EffReturn.java b/src/main/java/ch/njol/skript/effects/EffReturn.java index f2c8967dcb8..5ef3c2dc7ca 100644 --- a/src/main/java/ch/njol/skript/effects/EffReturn.java +++ b/src/main/java/ch/njol/skript/effects/EffReturn.java @@ -33,6 +33,9 @@ import ch.njol.util.Kleenean; import org.bukkit.event.Event; import org.eclipse.jdt.annotation.Nullable; +import org.jetbrains.annotations.UnknownNullability; + +import java.util.List; @Name("Return") @Description("Makes a trigger (e.g. a function) return a value") @@ -51,10 +54,9 @@ public class EffReturn extends Effect { ParserInstance.registerData(ReturnHandlerStack.class, ReturnHandlerStack::new); } - @SuppressWarnings("NotNullFieldNotInitialized") - private ReturnHandler handler; - @SuppressWarnings("NotNullFieldNotInitialized") - private Expression value; + private @UnknownNullability ReturnHandler handler; + private @UnknownNullability Expression value; + private @UnknownNullability List sectionsToExit; @Override @SuppressWarnings("unchecked") @@ -97,6 +99,7 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye } value = convertedExpr; + sectionsToExit = Section.getSectionsUntil((TriggerSection) handler); return true; } @@ -107,18 +110,14 @@ protected TriggerItem walk(Event event) { //noinspection rawtypes,unchecked ((ReturnHandler) handler).returnValues(event, value); - TriggerSection parent = getParent(); - while (parent != null && parent != handler) { - if (parent instanceof SectionExitHandler exitHandler) + for (TriggerSection section : sectionsToExit) { + if (section instanceof SectionExitHandler exitHandler) exitHandler.exit(event); - - parent = parent.getParent(); } - if (handler instanceof SectionExitHandler exitHandler) exitHandler.exit(event); - return null; + return ((TriggerSection) handler).getNext(); } @Override @@ -128,7 +127,7 @@ protected void execute(Event event) { @Override public ExecutionIntent executionIntent() { - return ExecutionIntent.stopTrigger(); + return ExecutionIntent.stopSections(sectionsToExit.size() + 1); } @Override diff --git a/src/main/java/ch/njol/skript/lang/Section.java b/src/main/java/ch/njol/skript/lang/Section.java index 6c4445c2634..d6f3ffa41ad 100644 --- a/src/main/java/ch/njol/skript/lang/Section.java +++ b/src/main/java/ch/njol/skript/lang/Section.java @@ -24,6 +24,7 @@ import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.lang.parser.ParserInstance; import ch.njol.util.Kleenean; +import com.google.common.base.Preconditions; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; @@ -171,6 +172,45 @@ protected void loadOptionalCode(SectionNode sectionNode) { getParser().setHasDelayBefore(Kleenean.UNKNOWN); } + /** + * Returns the sections from the current section (inclusive) until the specified section (exclusive). + * + * @param section The section to stop at. (exclusive) + * @return A list of sections from the current section (inclusive) until the specified section (exclusive). + */ + public static List getSectionsUntil(TriggerSection section) { + List sections = ParserInstance.get().getCurrentSections(); + return sections.subList(sections.indexOf(section) + 1, sections.size()); + } + + /** + * Returns a list of sections up to the specified number of levels. + * + * @param levels The number of levels to retrieve. + * @return A list of sections up to the specified number of levels. + */ + public static List getSections(int levels) { + Preconditions.checkArgument(levels > 0, "Depth must be at least 1"); + List sections = ParserInstance.get().getCurrentSections(); + return sections.subList(Math.max(sections.size() - levels, 0), sections.size()); + } + + /** + * Returns a list of sections to the specified number of levels. Only counting sections of the specified type. + * + * @param levels The number of levels to retrieve. + * @param type The class type of the sections to count. + * @return A list of sections of the specified type up to the specified number of levels. + */ + public static List getSections(int levels, Class type) { + Preconditions.checkArgument(levels > 0, "Depth must be at least 1"); + ParserInstance parser = ParserInstance.get(); + List sections = parser.getCurrentSections(type); + TriggerSection section = sections.get(Math.max(sections.size() - levels, 0)); + List allSections = parser.getCurrentSections(); + return allSections.subList(allSections.indexOf(section), allSections.size()); + } + @Nullable public static Section parse(String expr, @Nullable String defaultError, SectionNode sectionNode, List triggerItems) { SectionContext sectionContext = ParserInstance.get().getData(SectionContext.class);