-
Notifications
You must be signed in to change notification settings - Fork 15
Expand file tree
/
Copy pathExprRange.java
More file actions
101 lines (91 loc) · 4.13 KB
/
Copy pathExprRange.java
File metadata and controls
101 lines (91 loc) · 4.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package io.github.syst3ms.skriptparser.expressions;
import io.github.syst3ms.skriptparser.Parser;
import io.github.syst3ms.skriptparser.lang.Expression;
import io.github.syst3ms.skriptparser.lang.TriggerContext;
import io.github.syst3ms.skriptparser.lang.Variable;
import io.github.syst3ms.skriptparser.log.ErrorType;
import io.github.syst3ms.skriptparser.log.SkriptLogger;
import io.github.syst3ms.skriptparser.parsing.ParseContext;
import io.github.syst3ms.skriptparser.types.TypeManager;
import io.github.syst3ms.skriptparser.types.attributes.Range;
import io.github.syst3ms.skriptparser.types.comparisons.Comparators;
import io.github.syst3ms.skriptparser.types.comparisons.Relation;
import io.github.syst3ms.skriptparser.util.CollectionUtils;
import io.github.syst3ms.skriptparser.util.DoubleOptional;
/**
* Returns a range of values between two endpoints. Types supported by default are integers and characters (length 1 strings).
*
* @name Range
* @pattern [the] range from %object% [up|down]([ ]to| until) %object%
* @since ALPHA
* @author Syst3ms
*/
public class ExprRange implements Expression<Object> {
static {
Parser.getMainRegistration().addExpression(
ExprRange.class,
Object.class,
false,
"[the] range from %object% [up|down]([ ]to| until) %object%"
);
}
private Expression<?> from, to;
private TypeManager.IntersectionType intersectionType;
@Override
public boolean init(Expression<?>[] expressions, int matchedPattern, ParseContext parseContext) {
from = expressions[0];
to = expressions[1];
if (from instanceof Variable<?> || to instanceof Variable<?>)
return true;
var info = TypeManager.getByIntersection(Range.class, from.getReturnType(), to.getReturnType());
if (info.isEmpty()) {
SkriptLogger logger = parseContext.getLogger();
logger.error(
"Cannot get a range between "
+ from.toString(TriggerContext.DUMMY, logger.isDebug())
+ " and "
+ to.toString(TriggerContext.DUMMY, logger.isDebug()),
ErrorType.SEMANTIC_ERROR);
return false;
}
intersectionType = info.get();
return true;
}
@SuppressWarnings("unchecked")
@Override
public Object[] getValues(TriggerContext ctx) {
return DoubleOptional.ofOptional(from.getSingle(ctx), to.getSingle(ctx))
.mapToOptional((f, t) -> {
if (intersectionType == null) {
var info = TypeManager.getByIntersection(Range.class, f.getClass(), t.getClass());
// If it's still null, then no range can be found sadly...
if (info.isEmpty())
return null;
intersectionType = info.get();
}
// Convert the expressions to the intersection type
var fromConverted = intersectionType.convert(f);
var toConverted = intersectionType.convert(t);
if (fromConverted.isEmpty() || toConverted.isEmpty())
return null;
Range range = intersectionType.getType().getRange().orElseThrow();
// This is safe... right?
if (Comparators.compare(f, t) == Relation.GREATER) {
return CollectionUtils.reverseArray(range.apply(toConverted.get(), fromConverted.get()));
} else {
return range.apply(fromConverted.get(), toConverted.get());
}
})
.orElse(new Object[0]);
}
@Override
public Class<?> getReturnType() {
return intersectionType != null
? intersectionType.getType().getRange().orElseThrow().getRelativeType()
: Object.class;
}
@Override
public String toString(TriggerContext ctx, boolean debug) {
return "range from " + from.toString(ctx, debug) + " to " + to.toString(ctx, debug);
}
}