Skip to content

Commit c5fe6f6

Browse files
authored
Improve ExprElement to use iterators (#5183)
* Improve ExprElement to use iterators * Improve ExprElement to use iterators * Use colons in pattern * Add xth last element syntax * Add optional to * Add trailing new line
1 parent 62e414d commit c5fe6f6

File tree

2 files changed

+70
-30
lines changed

2 files changed

+70
-30
lines changed

Diff for: src/main/java/ch/njol/skript/expressions/ExprElement.java

+58-30
Original file line numberDiff line numberDiff line change
@@ -32,23 +32,29 @@
3232
import ch.njol.util.Kleenean;
3333
import ch.njol.util.StringUtils;
3434
import ch.njol.util.coll.CollectionUtils;
35+
import com.google.common.collect.Iterators;
3536
import org.bukkit.event.Event;
3637
import org.eclipse.jdt.annotation.Nullable;
3738

3839
import java.lang.reflect.Array;
40+
import java.util.Iterator;
3941

4042
@Name("Element of")
4143
@Description({"The first, last or a random element of a set, e.g. a list variable.",
4244
"See also: <a href='#ExprRandom'>random</a>"})
4345
@Examples("give a random element out of {free items::*} to the player")
44-
@Since("2.0")
46+
@Since("2.0, INSERT VERSION (relative to last element)")
4547
public class ExprElement extends SimpleExpression<Object> {
4648

4749
static {
48-
Skript.registerExpression(ExprElement.class, Object.class, ExpressionType.PROPERTY, "(-1¦[the] first|1¦[the] last|[a] random|%-number%(st|nd|rd|th)) element [out] of %objects%");
50+
Skript.registerExpression(ExprElement.class, Object.class, ExpressionType.PROPERTY, "(0:[the] first|1:[the] last|2:[a] random|3:[the] %-number%(st|nd|rd|th)|4:[the] %-number%(st|nd|rd|th) [to] last) element [out] of %objects%");
4951
}
5052

51-
private int element;
53+
private enum ElementType {
54+
FIRST, LAST, RANDOM, ORDINAL, TAIL_END_ORDINAL
55+
}
56+
57+
private ElementType type;
5258

5359
private Expression<?> expr;
5460

@@ -58,34 +64,56 @@ public class ExprElement extends SimpleExpression<Object> {
5864
@Override
5965
@SuppressWarnings("unchecked")
6066
public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
61-
expr = LiteralUtils.defendExpression(exprs[1]);
62-
number = (Expression<Number>) exprs[0];
63-
element = parseResult.mark;
67+
expr = LiteralUtils.defendExpression(exprs[2]);
68+
type = ElementType.values()[parseResult.mark];
69+
number = (Expression<Number>) (type == ElementType.ORDINAL ? exprs[0]: exprs[1]);
6470
return LiteralUtils.canInitSafely(expr);
6571
}
6672

6773
@Override
6874
@Nullable
69-
protected Object[] get(Event e) {
70-
Object[] os = expr.getArray(e);
71-
if (os.length == 0)
75+
protected Object[] get(Event event) {
76+
Iterator<?> iter = expr.iterator(event);
77+
if (iter == null || !iter.hasNext())
7278
return null;
73-
Object o;
74-
if (element == -1) {
75-
o = os[0];
76-
} else if (element == 1) {
77-
o = os[os.length - 1];
78-
} else if (element == 2) {
79-
Number number = this.number.getSingle(e);
80-
if (number == null || number.intValue() - 1 >= os.length || number.intValue() - 1 < 0)
81-
return null;
82-
o = os[number.intValue() - 1];
83-
} else {
84-
o = CollectionUtils.getRandom(os);
79+
Object element = null;
80+
switch (type) {
81+
case FIRST:
82+
element = iter.next();
83+
break;
84+
case LAST:
85+
element = Iterators.getLast(iter);
86+
break;
87+
case ORDINAL:
88+
assert this.number != null;
89+
Number number = this.number.getSingle(event);
90+
if (number == null)
91+
return null;
92+
try {
93+
element = Iterators.get(iter, number.intValue() - 1);
94+
} catch (IndexOutOfBoundsException exception) {
95+
return null;
96+
}
97+
break;
98+
case RANDOM:
99+
Object[] allIterValues = Iterators.toArray(iter, Object.class);
100+
element = CollectionUtils.getRandom(allIterValues);
101+
break;
102+
case TAIL_END_ORDINAL:
103+
allIterValues = Iterators.toArray(iter, Object.class);
104+
assert this.number != null;
105+
number = this.number.getSingle(event);
106+
if (number == null)
107+
return null;
108+
int ordinal = number.intValue();
109+
if (ordinal <= 0 || ordinal > allIterValues.length)
110+
return null;
111+
element = allIterValues[allIterValues.length - ordinal];
112+
break;
85113
}
86-
Object[] r = (Object[]) Array.newInstance(getReturnType(), 1);
87-
r[0] = o;
88-
return r;
114+
Object[] elementArray = (Object[]) Array.newInstance(getReturnType(), 1);
115+
elementArray[0] = element;
116+
return elementArray;
89117
}
90118

91119
@Override
@@ -97,7 +125,7 @@ public <R> Expression<? extends R> getConvertedExpression(Class<R>... to) {
97125
return null;
98126

99127
ExprElement exprElement = new ExprElement();
100-
exprElement.element = this.element;
128+
exprElement.type = this.type;
101129
exprElement.expr = convExpr;
102130
exprElement.number = this.number;
103131
return (Expression<? extends R>) exprElement;
@@ -116,17 +144,17 @@ public Class<?> getReturnType() {
116144
@Override
117145
public String toString(@Nullable Event e, boolean debug) {
118146
String prefix;
119-
switch (element) {
120-
case -1:
147+
switch (type) {
148+
case FIRST:
121149
prefix = "the first";
122150
break;
123-
case 1:
151+
case LAST:
124152
prefix = "the last";
125153
break;
126-
case 0:
154+
case RANDOM:
127155
prefix = "a random";
128156
break;
129-
case 2:
157+
case ORDINAL:
130158
assert number != null;
131159
prefix = "the ";
132160
// Proper ordinal number
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
test "ExprElement":
2+
set {_list::*} to "foo", "bar" and "foobar"
3+
assert first element of {_list::*} is "foo" with "Incorrect first element"
4+
assert last element of {_list::*} is "foobar" with "Incorrect last element"
5+
assert 2nd element of {_list::*} is "bar" with "Incorrect 2nd element"
6+
assert {_list::*} contains (random element of {_list::*}) with "Incorrect random element"
7+
assert 2nd to last element of {_list::*} is "bar" with "Incorrect 2nd last element"
8+
assert 3rd last element of {_list::*} is "foo" with "Incorrect 3rd last element"
9+
assert 100th last element of {_list::*} is not set with "Incorrect 100th last element"
10+
assert 1st last element of {_list::*} is "foobar" with "Incorrect 1st last element"
11+
assert 0th last element of {_list::*} is not set with "Incorrect 0th last element"
12+
assert -1th last element of {_list::*} is not set with "Incorrect -1th element"

0 commit comments

Comments
 (0)