Skip to content

Commit

Permalink
Add simple helper methods for getting relative sections
Browse files Browse the repository at this point in the history
  • Loading branch information
UnderscoreTud committed Sep 4, 2024
1 parent 0ab6a00 commit ce79b11
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 108 deletions.
61 changes: 21 additions & 40 deletions src/main/java/ch/njol/skript/effects/EffContinue.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.UnknownNullability;

import java.util.ArrayList;
import java.util.List;

@Name("Continue")
Expand Down Expand Up @@ -63,56 +62,36 @@ public class EffContinue extends Effect {
);
}

// Used for toString
private int level;

private @UnknownNullability LoopSection loop;
private @UnknownNullability List<LoopSection> innerLoops;
private int breakLevels;
private @UnknownNullability List<TriggerSection> innerSections;

@Override
@SuppressWarnings("unchecked")
public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
List<TriggerSection> sections = getParser().getCurrentSections();
innerLoops = new ArrayList<>();
int loopLevels = 0;
LoopSection lastLoop = null;

int level = matchedPattern == 0 ? -1 : ((Literal<Integer>) exprs[0]).getSingle();
level = matchedPattern == 0 ? -1 : ((Literal<Integer>) 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;
}

Expand All @@ -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");
}

}
98 changes: 42 additions & 56 deletions src/main/java/ch/njol/skript/effects/EffExit.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,106 +25,92 @@
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;

@Name("Exit")
@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("<i>unknown</i> (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<? extends TriggerSection>[] 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<TriggerSection> 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<? extends TriggerSection> 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<TriggerSection> 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
Expand Down
23 changes: 11 additions & 12 deletions src/main/java/ch/njol/skript/effects/EffReturn.java
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -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<TriggerSection> sectionsToExit;

@Override
@SuppressWarnings("unchecked")
Expand Down Expand Up @@ -97,6 +99,7 @@ public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelaye
}
value = convertedExpr;

sectionsToExit = Section.getSectionsUntil((TriggerSection) handler);
return true;
}

Expand All @@ -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
Expand All @@ -128,7 +127,7 @@ protected void execute(Event event) {

@Override
public ExecutionIntent executionIntent() {
return ExecutionIntent.stopTrigger();
return ExecutionIntent.stopSections(sectionsToExit.size() + 1);
}

@Override
Expand Down
40 changes: 40 additions & 0 deletions src/main/java/ch/njol/skript/lang/Section.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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<TriggerSection> getSectionsUntil(TriggerSection section) {
List<TriggerSection> 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<TriggerSection> getSections(int levels) {
Preconditions.checkArgument(levels > 0, "Depth must be at least 1");
List<TriggerSection> 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<TriggerSection> getSections(int levels, Class<? extends TriggerSection> type) {
Preconditions.checkArgument(levels > 0, "Depth must be at least 1");
ParserInstance parser = ParserInstance.get();
List<? extends TriggerSection> sections = parser.getCurrentSections(type);
TriggerSection section = sections.get(Math.max(sections.size() - levels, 0));
List<TriggerSection> allSections = parser.getCurrentSections();
return allSections.subList(allSections.indexOf(section), allSections.size());
}

@Nullable
public static Section parse(String expr, @Nullable String defaultError, SectionNode sectionNode, List<TriggerItem> triggerItems) {
SectionContext sectionContext = ParserInstance.get().getData(SectionContext.class);
Expand Down

0 comments on commit ce79b11

Please sign in to comment.