Skip to content

Commit 911bb91

Browse files
MweximMwexim
and
Mwexim
authored
Rework/expressions (#117)
* 💡 Expression (utility methods, changer rework, stricter changes) * 💡 VariableMap (better index ordering) * 💡 SyntaxParser (restrict lists to only allow the same type) * 💡 ExpressionList (revert restriction but improve lists instead) * 💡 CondExprContains/CondExprDateCompare * 💡 TaggedExpression (improved tag parsing for expression lists) * 💡 conditions (improved code & logic improvements) * 💡 expressions (apply improvements + property changes) * 🔥 ExprNumberConvertBase/ExprDateNow (merge conflicts) * 🔥 CondExprIsEmpty (fix CCE) * 🔥 CondExprContains (make use of stored comparator) * 💡 Expression (last #acceptsChange() changes and fixes) * 💡 PatternInfos (#toChoiceGroup() so properties can use it too) * 💡 PropertyConditional (removing TriggerContext parameter & better error messages) Co-authored-by: Mwexim <[email protected]>
1 parent 956a2b4 commit 911bb91

File tree

75 files changed

+905
-1017
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

75 files changed

+905
-1017
lines changed

src/main/java/io/github/syst3ms/skriptparser/effects/EffChange.java

+16-40
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,12 @@
55
import io.github.syst3ms.skriptparser.lang.Expression;
66
import io.github.syst3ms.skriptparser.lang.TriggerContext;
77
import io.github.syst3ms.skriptparser.log.ErrorType;
8-
import io.github.syst3ms.skriptparser.log.SkriptLogger;
98
import io.github.syst3ms.skriptparser.parsing.ParseContext;
109
import io.github.syst3ms.skriptparser.registration.PatternInfos;
11-
import io.github.syst3ms.skriptparser.types.Type;
1210
import io.github.syst3ms.skriptparser.types.TypeManager;
1311
import io.github.syst3ms.skriptparser.types.changers.ChangeMode;
14-
import io.github.syst3ms.skriptparser.util.ClassUtils;
15-
import io.github.syst3ms.skriptparser.util.StringUtils;
1612
import org.jetbrains.annotations.Nullable;
1713

18-
import java.util.Optional;
19-
2014
/**
2115
* A very general effect that can change many expressions. Many expressions can only be set and/or deleted, while some can have things added to or removed from them.
2216
*
@@ -54,31 +48,30 @@ public class EffChange extends Effect {
5448
@Nullable
5549
private Expression<?> changeWith;
5650
private ChangeMode mode;
57-
private boolean assignment; // A simple flag for identifying which syntax was precisely used
5851

5952
@Override
6053
public boolean init(Expression<?>[] expressions, int matchedPattern, ParseContext parseContext) {
6154
ChangeMode mode = PATTERNS.getInfo(matchedPattern);
6255
if (mode == ChangeMode.RESET || mode == ChangeMode.DELETE) {
6356
changed = expressions[0];
64-
} else if ((matchedPattern & 1) == 1 || mode == ChangeMode.SET) { // Notice the difference in the order of expressions
57+
} else if ((matchedPattern & 1) == 1 || mode == ChangeMode.SET) {
58+
// Notice the difference in the order of expressions
6559
changed = expressions[0];
6660
changeWith = expressions[1];
67-
assignment = (matchedPattern & 1) == 1;
6861
} else {
6962
changed = expressions[1];
7063
changeWith = expressions[0];
7164
}
7265
this.mode = mode;
73-
SkriptLogger logger = parseContext.getLogger();
66+
67+
var logger = parseContext.getLogger();
7468
String changedString = changed.toString(TriggerContext.DUMMY, logger.isDebug());
69+
7570
if (changeWith == null) {
7671
assert mode == ChangeMode.DELETE || mode == ChangeMode.RESET;
7772
return changed.acceptsChange(mode).isPresent();
7873
} else {
79-
Class<?> changeType = changeWith.getReturnType();
80-
Optional<Class<?>[]> acceptance = changed.acceptsChange(mode);
81-
if (acceptance.isEmpty()) {
74+
if (changed.acceptsChange(mode).isEmpty()) {
8275
switch (mode) {
8376
case SET:
8477
logger.error(changedString + " cannot be set to anything", ErrorType.SEMANTIC_ERROR);
@@ -90,19 +83,14 @@ public boolean init(Expression<?>[] expressions, int matchedPattern, ParseContex
9083
case REMOVE:
9184
logger.error("Nothing can be removed from " + changedString, ErrorType.SEMANTIC_ERROR);
9285
break;
93-
case DELETE:
94-
case RESET:
86+
default:
9587
throw new IllegalStateException();
9688
}
9789
return false;
98-
} else if (!ClassUtils.containsSuperclass(acceptance.get(), changeType)) {
99-
boolean array = changeType.isArray();
100-
Optional<? extends Type<?>> type = TypeManager.getByClassExact(changeType);
90+
} else if (!changed.acceptsChange(mode, changeWith)) {
91+
var type = TypeManager.getByClassExact(changeWith.getReturnType());
10192
assert type.isPresent();
102-
String changeTypeName = StringUtils.withIndefiniteArticle(
103-
type.get().getPluralForms()[array ? 1 : 0],
104-
array
105-
);
93+
String changeTypeName = type.get().withIndefiniteArticle(!changeWith.isSingle());
10694
switch (mode) {
10795
case SET:
10896
logger.error(changedString + " cannot be set to " + changeTypeName, ErrorType.SEMANTIC_ERROR);
@@ -127,12 +115,12 @@ public boolean init(Expression<?>[] expressions, int matchedPattern, ParseContex
127115
@Override
128116
public void execute(TriggerContext ctx) {
129117
if (changeWith == null) {
130-
changed.change(ctx, new Object[0], mode);
118+
changed.change(ctx, mode, new Object[0]);
131119
} else {
132-
var values= changeWith.getValues(ctx);
120+
var values = changeWith.getValues(ctx);
133121
if (values.length == 0)
134122
return;
135-
changed.change(ctx, values, mode);
123+
changed.change(ctx, mode, values);
136124
}
137125
}
138126

@@ -142,23 +130,11 @@ public String toString(TriggerContext ctx, boolean debug) {
142130
String changedWithString = changeWith != null ? changeWith.toString(ctx, debug) : "";
143131
switch (mode) {
144132
case SET:
145-
if (assignment) {
146-
return String.format("%s = %s", changedString, changedWithString);
147-
} else {
148-
return String.format("set %s to %s", changedString, changedWithString);
149-
}
133+
return String.format("set %s to %s", changedString, changedWithString);
150134
case ADD:
151-
if (assignment) {
152-
return String.format("%s += %s", changedString, changedWithString);
153-
} else {
154-
return String.format("add %s to %s", changedWithString, changedString);
155-
}
135+
return String.format("add %s to %s", changedWithString, changedString);
156136
case REMOVE:
157-
if (assignment) {
158-
return String.format("%s -= %s", changedString, changedWithString);
159-
} else {
160-
return String.format("remove %s from %s", changedWithString, changedString);
161-
}
137+
return String.format("remove %s from %s", changedWithString, changedString);
162138
case DELETE:
163139
case RESET:
164140
return String.format("%s %s", mode.name().toLowerCase(), changedString);

src/main/java/io/github/syst3ms/skriptparser/effects/EffPrint.java

+6-7
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
import io.github.syst3ms.skriptparser.lang.Effect;
55
import io.github.syst3ms.skriptparser.lang.Expression;
66
import io.github.syst3ms.skriptparser.lang.TriggerContext;
7+
import io.github.syst3ms.skriptparser.lang.base.TaggedExpression;
78
import io.github.syst3ms.skriptparser.parsing.ParseContext;
8-
import io.github.syst3ms.skriptparser.util.StringUtils;
99

1010
/**
1111
* Prints some text to the console
@@ -23,25 +23,24 @@ public class EffPrint extends Effect {
2323
);
2424
}
2525

26-
private Expression<String> string;
26+
private Expression<String> expression;
2727

2828
@SuppressWarnings("unchecked")
2929
@Override
3030
public boolean init(Expression<?>[] expressions, int matchedPattern, ParseContext parseContext) {
31-
string = (Expression<String>) expressions[0];
31+
expression = (Expression<String>) expressions[0];
3232
return true;
3333
}
3434

3535
@Override
3636
public void execute(TriggerContext ctx) {
37-
String[] strs = StringUtils.applyTags(string, ctx, "console");
38-
for (String str : strs) {
39-
System.out.println(str);
37+
for (String val : TaggedExpression.apply(expression, ctx, "console")) {
38+
System.out.println(val);
4039
}
4140
}
4241

4342
@Override
4443
public String toString(TriggerContext ctx, boolean debug) {
45-
return "print " + string.toString(ctx, debug);
44+
return "print " + expression.toString(ctx, debug);
4645
}
4746
}

src/main/java/io/github/syst3ms/skriptparser/expressions/CondExprCompare.java

+3-13
Original file line numberDiff line numberDiff line change
@@ -215,16 +215,6 @@ private boolean initComparator() {
215215

216216
if (f == Object.class || s == Object.class) {
217217
return true;
218-
} else if (f != s) {
219-
// Tries to convert the instances to each other.
220-
// Basically takes expression conversions into account.
221-
var converted = Expression.convertPair(first, second);
222-
if (!first.equals(converted.getFirst()) || !second.equals(converted.getSecond())) {
223-
first = converted.getFirst();
224-
second = converted.getSecond();
225-
comparator = (Comparator<Object, Object>) Comparators.getComparator(first.getReturnType(), second.getReturnType()).orElseThrow(AssertionError::new);
226-
return true;
227-
}
228218
}
229219
return (comparator = (Comparator<Object, Object>) Comparators.getComparator(f, s).orElse(null)) != null;
230220
}
@@ -265,9 +255,9 @@ private boolean initComparator() {
265255
*/
266256
@Override
267257
public boolean check(TriggerContext ctx) {
268-
Object[] firstValues = first.getValues(ctx);
269-
Object[] secondValues = second.getValues(ctx);
270-
Object[] thirdValues = third != null ? third.getValues(ctx) : null;
258+
Object[] firstValues = first.getArray(ctx);
259+
Object[] secondValues = second.getArray(ctx);
260+
Object[] thirdValues = third != null ? third.getArray(ctx) : null;
271261
if (thirdValues == null) {
272262
if (firstEach && secondEach) {
273263
if (firstValues.length != secondValues.length)

src/main/java/io/github/syst3ms/skriptparser/expressions/CondExprContains.java

+53-15
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44
import io.github.syst3ms.skriptparser.lang.Expression;
55
import io.github.syst3ms.skriptparser.lang.TriggerContext;
66
import io.github.syst3ms.skriptparser.lang.base.ConditionalExpression;
7+
import io.github.syst3ms.skriptparser.log.ErrorType;
78
import io.github.syst3ms.skriptparser.parsing.ParseContext;
8-
import io.github.syst3ms.skriptparser.util.CollectionUtils;
9-
10-
import java.util.Optional;
9+
import io.github.syst3ms.skriptparser.types.comparisons.Comparator;
10+
import io.github.syst3ms.skriptparser.types.comparisons.Comparators;
11+
import io.github.syst3ms.skriptparser.types.comparisons.Relation;
12+
import io.github.syst3ms.skriptparser.util.DoubleOptional;
13+
import org.jetbrains.annotations.Nullable;
1114

1215
/**
1316
* See if a given list of objects contain a given element.
@@ -16,7 +19,7 @@
1619
* @name Contain
1720
* @type CONDITION
1821
* @pattern %string% [does(n't| not)] contain[s] %string%
19-
* @pattern %objects% [do[es](n't| not)] contain[s] %object%
22+
* @pattern %objects% [do[es](n't| not)] contain[s] %objects%
2023
* @since ALPHA
2124
* @author Mwexim
2225
*/
@@ -28,33 +31,68 @@ public class CondExprContains extends ConditionalExpression {
2831
true,
2932
2,
3033
"%string% [1:does(n't| not)] contain[s] %string%",
31-
"%objects% [1:do[es](n't| not)] contain[s] %object%"
34+
"%objects% [1:do[es](n't| not)] contain[s] %objects%"
3235
);
3336
}
3437

35-
private Expression<?> first, second;
38+
private Expression<Object> first, second;
39+
@Nullable
40+
private Comparator<Object, Object> comparator;
3641
private boolean onlyString;
3742

43+
@SuppressWarnings("unchecked")
3844
@Override
3945
public boolean init(Expression<?>[] expressions, int matchedPattern, ParseContext parseContext) {
40-
first = expressions[0];
41-
second = expressions[1];
46+
first = (Expression<Object>) expressions[0];
47+
second = (Expression<Object>) expressions[1];
48+
comparator = (Comparator<Object, Object>) Comparators.getComparator(first.getReturnType(), second.getReturnType()).orElse(null);
49+
// If the expressions are variables, their return type is unknown at parse time
50+
if (first.getReturnType() != Object.class
51+
&& second.getReturnType() != Object.class
52+
&& comparator == null) {
53+
var logger = parseContext.getLogger();
54+
logger.error(
55+
"'" +
56+
first.toString(TriggerContext.DUMMY, logger.isDebug()) +
57+
"' can never contain '" +
58+
second.toString(TriggerContext.DUMMY, logger.isDebug()) +
59+
"' because their values cannot be compared",
60+
ErrorType.SEMANTIC_ERROR
61+
);
62+
return false;
63+
}
64+
4265
onlyString = matchedPattern == 0;
4366
setNegated(parseContext.getNumericMark() == 1);
67+
if (!onlyString && !first.isAndList()) {
68+
parseContext.getLogger().error(
69+
"An or-list cannot contain any values",
70+
ErrorType.SEMANTIC_ERROR,
71+
"If you want to check if an or-list 'contains' a value, you should do an equality check instead."
72+
);
73+
return false;
74+
}
4475
return true;
4576
}
4677

47-
@SuppressWarnings("unchecked")
4878
@Override
4979
public boolean check(TriggerContext ctx) {
5080
if (onlyString) {
51-
Optional<? extends String> f = ((Expression<String>) first).getSingle(ctx);
52-
Optional<? extends String> s = ((Expression<String>) second).getSingle(ctx);
53-
return isNegated() != f.filter(o1 -> s.map(o1::contains).isPresent()).isPresent();
81+
return isNegated() != DoubleOptional.ofOptional(first.getSingle(ctx), second.getSingle(ctx))
82+
.map(toCheck -> (String) toCheck, toMatch -> (String) toMatch)
83+
.mapToOptional(String::contains)
84+
.orElse(false);
5485
} else {
55-
Object[] f = ((Expression<Object>) first).getValues(ctx);
56-
Object[] s = ((Expression<Object>) second).getValues(ctx);
57-
return isNegated() != CollectionUtils.contains(f, s);
86+
return second.check(
87+
ctx,
88+
toMatch -> Expression.check(
89+
first.getValues(ctx),
90+
toCheck -> (comparator == null ? Comparators.compare(toCheck, toMatch) : comparator.apply(toCheck, toMatch)).is(Relation.EQUAL),
91+
false,
92+
!first.isAndList()
93+
),
94+
isNegated()
95+
);
5896
}
5997
}
6098

src/main/java/io/github/syst3ms/skriptparser/expressions/CondExprDateCompare.java

+9-8
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import io.github.syst3ms.skriptparser.lang.TriggerContext;
66
import io.github.syst3ms.skriptparser.lang.base.ConditionalExpression;
77
import io.github.syst3ms.skriptparser.parsing.ParseContext;
8-
import io.github.syst3ms.skriptparser.util.DoubleOptional;
98
import io.github.syst3ms.skriptparser.util.SkriptDate;
109

1110
import java.time.Duration;
@@ -26,8 +25,8 @@ public class CondExprDateCompare extends ConditionalExpression {
2625
CondExprDateCompare.class,
2726
Boolean.class,
2827
true,
29-
"%date% (was|were)( more|(n't| not) less) than %duration% [ago]",
30-
"%date% (was|were)((n't| not) more| less) than %duration% [ago]"
28+
"%dates% (was|were)( more|(n't| not) less) than %duration% [ago]",
29+
"%dates% (was|were)((n't| not) more| less) than %duration% [ago]"
3130
);
3231
}
3332

@@ -45,11 +44,13 @@ public boolean init(Expression<?>[] expressions, int matchedPattern, ParseContex
4544

4645
@Override
4746
public boolean check(TriggerContext ctx) {
48-
return DoubleOptional.ofOptional(date.getSingle(ctx), duration.getSingle(ctx))
49-
.filter(
50-
(dat, dur) -> isNegated() != (dat.getTimestamp() < SkriptDate.now().getTimestamp() - dur.toMillis())
51-
)
52-
.isPresent();
47+
return date.check(
48+
ctx,
49+
toCheck -> duration.getSingle(ctx)
50+
.filter(toCompare -> toCheck.compareTo(SkriptDate.now().minus(toCompare)) < 0)
51+
.isPresent(),
52+
isNegated()
53+
);
5354
}
5455

5556
@Override

src/main/java/io/github/syst3ms/skriptparser/expressions/CondExprIsDivisible.java

+9-10
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import io.github.syst3ms.skriptparser.util.math.BigDecimalMath;
1010

1111
import java.math.BigInteger;
12-
import java.util.Arrays;
1312

1413
/**
1514
* Check if a given number is divisible by another number.
@@ -42,15 +41,15 @@ public boolean init(Expression<?>[] expressions, int matchedPattern, ParseContex
4241
}
4342

4443
@Override
45-
public boolean check(TriggerContext ctx, Number[] performers) {
46-
if (performers.length == 0)
47-
return isNegated();
48-
return isNegated() != Arrays.stream(performers)
49-
.allMatch(val -> divider.getSingle(ctx)
50-
.filter(__ -> BigDecimalMath.isIntValue(BigDecimalMath.getBigDecimal(val)))
51-
.filter(d -> BigDecimalMath.getBigInteger(val).mod(d).equals(BigInteger.ZERO))
52-
.isPresent()
53-
);
44+
public boolean check(TriggerContext ctx) {
45+
return getPerformer().check(
46+
ctx,
47+
performer -> divider.getSingle(ctx)
48+
.filter(__ -> BigDecimalMath.isIntValue(BigDecimalMath.getBigDecimal(performer)))
49+
.filter(val -> BigDecimalMath.getBigInteger(performer).mod(val).equals(BigInteger.ZERO))
50+
.isPresent(),
51+
isNegated()
52+
);
5453
}
5554

5655
@Override

0 commit comments

Comments
 (0)