Skip to content

🚀 Add loop-counter & Improve loops #4595

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 46 commits into from
Jun 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
01fbfe0
🚀 Add `fails at` to while loop
AyhamAl-Ali Feb 11, 2022
d3397f3
Add iteration counter expr
AyhamAl-Ali Feb 12, 2022
5534c34
Merge branch 'master' into ench/while-fails-at
AyhamAl-Ali Feb 13, 2022
6ff2f24
🚀 Add loop-counter
AyhamAl-Ali Mar 30, 2022
691e37c
Extra protection
AyhamAl-Ali Mar 30, 2022
1c44447
Merge branch 'master' into ench/while-fails-at
AyhamAl-Ali Mar 30, 2022
72f4164
Should be ready now
AyhamAl-Ali Apr 5, 2022
6f9068c
Merge branch 'master' into ench/while-fails-at
AyhamAl-Ali Apr 5, 2022
d2314fd
Merge branch 'master' into ench/while-fails-at
AyhamAl-Ali Jun 24, 2022
58ccb26
Update src/main/java/ch/njol/skript/expressions/ExprLoopValue.java
AyhamAl-Ali Jul 1, 2022
56c5b68
Merge branch 'master' into ench/while-fails-at
AyhamAl-Ali Jul 1, 2022
674e7c2
RC - Update EffContinue with new LoopSection & Update loop-value
AyhamAl-Ali Jul 1, 2022
66244af
Update description
AyhamAl-Ali Jul 1, 2022
174fb7d
Merge branch 'master' into ench/while-fails-at
AyhamAl-Ali Jul 1, 2022
7ec6b41
Update src/main/java/ch/njol/skript/effects/EffContinue.java
AyhamAl-Ali Jul 1, 2022
4932f49
Merge branch 'master' into ench/while-fails-at
AyhamAl-Ali Jul 1, 2022
75e8f92
Improvements
AyhamAl-Ali Jul 1, 2022
14c8cb6
Merge remote-tracking branch 'AyhamAl-Ali/ench/while-fails-at' into e…
AyhamAl-Ali Jul 1, 2022
d3e3d6d
Annotations
AyhamAl-Ali Jul 1, 2022
cad44b3
Update src/main/java/ch/njol/skript/expressions/ExprLoopIteration.java
AyhamAl-Ali Jul 9, 2022
4161e68
Update src/main/java/ch/njol/skript/expressions/ExprLoopIteration.java
AyhamAl-Ali Jul 15, 2022
d7816d3
Update src/main/java/ch/njol/skript/expressions/ExprLoopIteration.java
AyhamAl-Ali Jul 18, 2022
85f1775
Update error message
AyhamAl-Ali Jul 18, 2022
f5e2a4c
Merge remote-tracking branch 'AyhamAl-Ali/ench/while-fails-at' into e…
AyhamAl-Ali Jul 18, 2022
8cd9c34
Update src/main/java/ch/njol/skript/expressions/ExprLoopIteration.java
AyhamAl-Ali Jul 22, 2022
875cb15
Update src/main/java/ch/njol/skript/lang/LoopSection.java
AyhamAl-Ali Aug 6, 2022
7c1e5b6
Update src/main/java/ch/njol/skript/expressions/ExprLoopValue.java
AyhamAl-Ali Aug 6, 2022
a71f19e
Update src/main/java/ch/njol/skript/sections/SecLoop.java
AyhamAl-Ali Aug 7, 2022
d43da59
Update src/main/java/ch/njol/skript/sections/SecLoop.java
AyhamAl-Ali Aug 7, 2022
a3e111d
Update src/main/java/ch/njol/skript/expressions/ExprLoopIteration.java
AyhamAl-Ali Aug 7, 2022
c98a4f3
Apply suggestions from code review
AyhamAl-Ali Aug 7, 2022
8d4c2e0
Formatting Improvements
AyhamAl-Ali Aug 26, 2022
a32d070
Update src/main/java/ch/njol/skript/effects/EffContinue.java
AyhamAl-Ali Nov 25, 2022
92cde7b
Better variable naming
AyhamAl-Ali Jan 1, 2023
1623b9d
Merge remote-tracking branch 'AyhamAl-Ali/ench/while-fails-at' into e…
AyhamAl-Ali Jan 1, 2023
60e31ba
Examples formatting
AyhamAl-Ali Jan 1, 2023
f7f7329
Requested Changes
AyhamAl-Ali Apr 18, 2023
9bf0f77
Add tests
AyhamAl-Ali Apr 18, 2023
c8c5ed3
Merge remote-tracking branch 'origin/master' into ench/while-fails-at
AyhamAl-Ali Apr 18, 2023
17c4ca5
Apply suggestions from code review
AyhamAl-Ali Apr 19, 2023
ab32194
Reorder methods
AyhamAl-Ali Apr 19, 2023
511d89b
Merge remote-tracking branch 'AyhamAl-Ali/ench/while-fails-at' into e…
AyhamAl-Ali Apr 19, 2023
8d609c2
Update src/test/skript/tests/regressions/4595-loop-iteration.sk
AyhamAl-Ali Apr 20, 2023
08351d2
Merge branch 'master' into ench/while-fails-at
TheLimeGlass Jun 6, 2023
48862ac
Merge branch 'master' into ench/while-fails-at
TheLimeGlass Jun 25, 2023
128bdc8
Merge branch 'master' into ench/while-fails-at
TheLimeGlass Jun 26, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 27 additions & 21 deletions src/main/java/ch/njol/skript/effects/EffContinue.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,25 +25,33 @@
import ch.njol.skript.doc.Since;
import ch.njol.skript.lang.Effect;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.LoopSection;
import ch.njol.skript.lang.SkriptParser.ParseResult;
import ch.njol.skript.lang.TriggerItem;
import ch.njol.skript.lang.TriggerSection;
import ch.njol.skript.lang.parser.ParserInstance;
import ch.njol.skript.sections.SecLoop;
import ch.njol.skript.sections.SecWhile;
import ch.njol.util.Kleenean;
import org.bukkit.event.Event;
import org.eclipse.jdt.annotation.Nullable;

import java.util.List;
import java.util.stream.Collectors;

@Name("Continue")
@Description("Skips the value currently being looped, moving on to the next value if it exists.")
@Examples({"loop all players:",
@Description("Immediately moves the (while) loop on to the next iteration.")
@Examples({
"# Broadcast online moderators",
"loop all players:",
"\tif loop-value does not have permission \"moderator\":",
"\t\tcontinue # filter out non moderators",
"\tbroadcast \"%loop-player% is a moderator!\" # Only moderators get broadcast"})
"\t\tcontinue # filter out non moderators",
"\tbroadcast \"%loop-player% is a moderator!\" # Only moderators get broadcast",
" ",
"# Game starting counter",
"set {_counter} to 11",
"while {_counter} > 0:",
"\tremove 1 from {_counter}",
"\twait a second",
"\tif {_counter} != 1, 2, 3, 5 or 10:",
"\t\tcontinue # only print when counter is 1, 2, 3, 5 or 10",
"\tbroadcast \"Game starting in %{_counter}% second(s)\"",
})
@Since("2.2-dev37, 2.7 (while loops)")
public class EffContinue extends Effect {

Expand All @@ -52,36 +60,34 @@ public class EffContinue extends Effect {
}

@SuppressWarnings("NotNullFieldNotInitialized")
private TriggerSection section;
private LoopSection loop;

@Override
public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
List<TriggerSection> currentSections = ParserInstance.get().getCurrentSections().stream()
.filter(s -> s instanceof SecLoop || s instanceof SecWhile)
.collect(Collectors.toList());
List<LoopSection> currentLoops = getParser().getCurrentSections(LoopSection.class);

if (currentSections.isEmpty()) {
Skript.error("Continue may only be used in while or loops");
if (currentLoops.isEmpty()) {
Skript.error("The 'continue' effect may only be used in while and regular loops");
return false;
}

section = currentSections.get(currentSections.size() - 1);
loop = currentLoops.get(currentLoops.size() - 1);
return true;
}

@Override
protected void execute(Event e) {
protected void execute(Event event) {
throw new UnsupportedOperationException();
}

@Nullable
@Override
protected TriggerItem walk(Event e) {
return section;
@Nullable
protected TriggerItem walk(Event event) {
return loop;
}

@Override
public String toString(@Nullable Event e, boolean debug) {
public String toString(@Nullable Event event, boolean debug) {
return "continue";
}

Expand Down
72 changes: 35 additions & 37 deletions src/main/java/ch/njol/skript/effects/EffExit.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,50 +25,51 @@
import ch.njol.skript.doc.Since;
import ch.njol.skript.lang.Effect;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.LoopSection;
import ch.njol.skript.lang.SkriptParser.ParseResult;
import ch.njol.skript.lang.TriggerItem;
import ch.njol.skript.lang.TriggerSection;
import ch.njol.skript.lang.parser.ParserInstance;
import ch.njol.skript.log.ErrorQuality;
import ch.njol.skript.sections.SecConditional;
import ch.njol.skript.sections.SecLoop;
import ch.njol.skript.sections.SecWhile;
import ch.njol.util.Kleenean;
import org.bukkit.event.Event;
import org.eclipse.jdt.annotation.Nullable;

import java.util.List;

/**
* @author Peter Güttinger
*/
@Name("Exit")
@Description("Exits a given amount of loops and conditionals, or the entire trigger.")
@Examples({"if player has any ore:",
" stop",
"message \"%player% has no ores!\"",
"loop blocks above the player:",
" loop-block is not air:",
" exit 2 sections",
" set loop-block to water"})
@Examples({
"if player has any ore:",
"\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"
})
@Since("<i>unknown</i> (before 2.1)")
public class EffExit extends Effect { // TODO [code style] warn user about code after a stop 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) [(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 final static int EVERYTHING = 0, LOOPS = 1, CONDITIONALS = 2;
private final static String[] names = {"sections", "loops", "conditionals"};
private static final int EVERYTHING = 0;
private static final int LOOPS = 1;
private static final int CONDITIONALS = 2;
private static final String[] names = {"sections", "loops", "conditionals"};
private int type;

@Override
public boolean init(final Expression<?>[] exprs, final int matchedPattern, final Kleenean isDelayed, final ParseResult parser) {
public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parser) {
switch (matchedPattern) {
case 0:
breakLevels = getParser().getCurrentSections().size() + 1;
Expand Down Expand Up @@ -102,44 +103,41 @@ private static int numLevels(int type) {
List<TriggerSection> currentSections = ParserInstance.get().getCurrentSections();
if (type == EVERYTHING)
return currentSections.size();
int r = 0;
for (TriggerSection s : currentSections) {
if (type == CONDITIONALS ? s instanceof SecConditional : s instanceof SecLoop || s instanceof SecWhile)
r++;
int level = 0;
for (TriggerSection section : currentSections) {
if (type == CONDITIONALS ? section instanceof SecConditional : section instanceof LoopSection)
level++;
}
return r;
return level;
}

@Override
@Nullable
protected TriggerItem walk(final Event e) {
debug(e, false);
TriggerItem n = this;
protected TriggerItem walk(Event event) {
debug(event, false);
TriggerItem node = this;
for (int i = breakLevels; i > 0;) {
n = n.getParent();
if (n == null) {
node = node.getParent();
if (node == null) {
assert false : this;
return null;
}
if (n instanceof SecLoop) {
((SecLoop) n).exit(e);
} else if (n instanceof SecWhile) {
((SecWhile) n).reset();
}
if (node instanceof LoopSection)
((LoopSection) node).exit(event);

if (type == EVERYTHING || type == CONDITIONALS && n instanceof SecConditional || type == LOOPS && (n instanceof SecLoop || n instanceof SecWhile))
if (type == EVERYTHING || type == CONDITIONALS && node instanceof SecConditional || type == LOOPS && (node instanceof LoopSection))
i--;
}
return n instanceof SecLoop ? ((SecLoop) n).getActualNext() : n instanceof SecWhile ? ((SecWhile) n).getActualNext() : n.getNext();
return node instanceof LoopSection ? ((LoopSection) node).getActualNext() : node.getNext();
}

@Override
protected void execute(final Event e) {
protected void execute(Event event) {
assert false;
}

@Override
public String toString(final @Nullable Event e, final boolean debug) {
public String toString(@Nullable Event event, boolean debug) {
return "stop " + breakLevels + " " + names[type];
}

Expand Down
56 changes: 26 additions & 30 deletions src/main/java/ch/njol/skript/effects/EffReturn.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import ch.njol.skript.doc.Since;
import ch.njol.skript.lang.Effect;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.LoopSection;
import ch.njol.skript.lang.SkriptParser.ParseResult;
import ch.njol.skript.lang.TriggerItem;
import ch.njol.skript.lang.TriggerSection;
Expand All @@ -34,19 +35,16 @@
import ch.njol.skript.lang.function.ScriptFunction;
import ch.njol.skript.log.RetainingLogHandler;
import ch.njol.skript.log.SkriptLogger;
import ch.njol.skript.sections.SecLoop;
import ch.njol.skript.sections.SecWhile;
import ch.njol.util.Kleenean;
import org.bukkit.event.Event;
import org.eclipse.jdt.annotation.Nullable;

/**
* @author Peter Güttinger
*/
@Name("Return")
@Description("Makes a function return a value")
@Examples({"function double(i: number) :: number:",
" return 2 * {_i}"})
@Examples({
"function double(i: number) :: number:",
"\treturn 2 * {_i}"
})
@Since("2.2")
public class EffReturn extends Effect {

Expand Down Expand Up @@ -75,66 +73,64 @@ public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelaye
}

function = f;
ClassInfo<?> rt = function.getReturnType();
if (rt == null) {
ClassInfo<?> returnType = function.getReturnType();
if (returnType == null) {
Skript.error("This function doesn't return any value. Please use 'stop' or 'exit' if you want to stop the function.");
return false;
}

RetainingLogHandler log = SkriptLogger.startRetainingLog();
Expression<?> v;
Expression<?> convertedExpr;
try {
v = exprs[0].getConvertedExpression(rt.getC());
if (v == null) {
log.printErrors("This function is declared to return " + rt.getName().withIndefiniteArticle() + ", but " + exprs[0].toString(null, false) + " is not of that type.");
convertedExpr = exprs[0].getConvertedExpression(returnType.getC());
if (convertedExpr == null) {
log.printErrors("This function is declared to return " + returnType.getName().withIndefiniteArticle() + ", but " + exprs[0].toString(null, false) + " is not of that type.");
return false;
}
log.printLog();
} finally {
log.stop();
}

if (f.isSingle() && !v.isSingle()) {
Skript.error("This function is defined to only return a single " + rt.toString() + ", but this return statement can return multiple values.");
if (f.isSingle() && !convertedExpr.isSingle()) {
Skript.error("This function is defined to only return a single " + returnType.toString() + ", but this return statement can return multiple values.");
return false;
}
value = v;
value = convertedExpr;

return true;
}

@SuppressWarnings({"unchecked", "rawtypes"})
@Override
@Nullable
protected TriggerItem walk(final Event e) {
debug(e, false);
if (e instanceof FunctionEvent) {
((ScriptFunction) function).setReturnValue(value.getArray(e));
@SuppressWarnings({"unchecked", "rawtypes"})
protected TriggerItem walk(Event event) {
debug(event, false);
if (event instanceof FunctionEvent) {
((ScriptFunction) function).setReturnValue(value.getArray(event));
} else {
assert false : e;
assert false : event;
}

TriggerSection parent = getParent();
while (parent != null) {
if (parent instanceof SecLoop) {
((SecLoop) parent).exit(e);
} else if (parent instanceof SecWhile) {
((SecWhile) parent).reset();
}
if (parent instanceof LoopSection)
((LoopSection) parent).exit(event);

parent = parent.getParent();
}

return null;
}

@Override
protected void execute(Event e) {
protected void execute(Event event) {
assert false;
}

@Override
public String toString(@Nullable Event e, boolean debug) {
return "return " + value.toString(e, debug);
public String toString(@Nullable Event event, boolean debug) {
return "return " + value.toString(event, debug);
}

}
Loading