Skip to content

Commit 1afb977

Browse files
committed
Improve property resolution, add back-compat for AnyNamed, AnyContains, start parse-time checks for Contains
1 parent 85122a3 commit 1afb977

10 files changed

Lines changed: 112 additions & 19 deletions

File tree

src/main/java/ch/njol/skript/classes/AnyInfo.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
*
1414
* @see AnyProvider
1515
*/
16+
@Deprecated(since="INSERT VERSION")
1617
public class AnyInfo<Type extends AnyProvider> extends ClassInfo<Type> {
1718

1819
/**

src/main/java/ch/njol/skript/classes/data/SkriptClasses.java

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import ch.njol.skript.aliases.ItemType;
88
import ch.njol.skript.bukkitutil.ItemUtils;
99
import ch.njol.skript.classes.*;
10+
import ch.njol.skript.classes.Changer.ChangeMode;
1011
import ch.njol.skript.config.Config;
1112
import ch.njol.skript.config.Node;
1213
import ch.njol.skript.expressions.base.EventValueExpression;
@@ -227,14 +228,14 @@ public String name(ItemType itemType) {
227228
}
228229

229230
@Override
230-
public Class<?> @Nullable [] acceptChange(Changer.ChangeMode mode) {
231-
if (mode == Changer.ChangeMode.SET || mode == Changer.ChangeMode.RESET)
231+
public Class<?> @Nullable [] acceptChange(ChangeMode mode) {
232+
if (mode == ChangeMode.SET || mode == ChangeMode.RESET)
232233
return new Class[] {String.class};
233234
return null;
234235
}
235236

236237
@Override
237-
public void change(ItemType itemType, Object @Nullable [] delta, Changer.ChangeMode mode) {
238+
public void change(ItemType itemType, Object @Nullable [] delta, ChangeMode mode) {
238239
String name = delta != null ? (String) delta[0] : null;
239240
itemType.setName(name);
240241
}
@@ -958,14 +959,43 @@ public String toVariableNameString(DynamicFunctionReference<?> function) {
958959
}
959960
}));
960961

962+
//noinspection deprecation
961963
Classes.registerClass(new AnyInfo<>(AnyNamed.class, "named")
962964
.name("Any Named Thing")
963965
.description("Something that has a name (e.g. an item).")
964966
.usage("")
965967
.examples("{thing}'s name")
966968
.since("2.10")
969+
.property(Property.NAME, new Property.NameHandler<AnyNamed, String>() {
970+
971+
@Override
972+
public @NotNull Class<String> returnType() {
973+
return String.class;
974+
}
975+
976+
@Override
977+
public String name(AnyNamed anyNamed) {
978+
return anyNamed.name();
979+
}
980+
981+
@Override
982+
public Class<?> @Nullable [] acceptChange(ChangeMode mode) {
983+
if (mode == ChangeMode.SET)
984+
return new Class[] {String.class};
985+
return null;
986+
}
987+
988+
@Override
989+
public void change(AnyNamed named, Object @Nullable [] delta, ChangeMode mode) {
990+
if (mode == ChangeMode.SET && named.supportsNameChange()) {
991+
assert delta != null;
992+
named.setName((String) delta[0]);
993+
}
994+
}
995+
})
967996
);
968997

998+
//noinspection deprecation
969999
Classes.registerClass(new AnyInfo<>(AnyAmount.class, "numbered")
9701000
.name("Any Numbered/Sized Thing")
9711001
.description("Something that has an amount or size.")
@@ -974,6 +1004,7 @@ public String toVariableNameString(DynamicFunctionReference<?> function) {
9741004
.since("2.10")
9751005
);
9761006

1007+
//noinspection deprecation
9771008
Classes.registerClass(new AnyInfo<>(AnyValued.class, "valued")
9781009
.name("Any Valued Thing")
9791010
.description("Something that has a value.")
@@ -982,13 +1013,25 @@ public String toVariableNameString(DynamicFunctionReference<?> function) {
9821013
.since("2.10")
9831014
);
9841015

1016+
//noinspection deprecation
9851017
Classes.registerClass(new AnyInfo<>(AnyContains.class, "containing")
9861018
.user("any container")
9871019
.name("Anything with Contents")
9881020
.description("Something that contains other things.")
9891021
.usage("")
9901022
.examples("{a} contains {b}")
9911023
.since("2.10")
1024+
.property(Property.CONTAINS, new Property.ContainsHandler<AnyContains, Object>() {
1025+
@Override
1026+
public boolean contains(AnyContains anyContains, Object object) {
1027+
return anyContains.checkSafely(object);
1028+
}
1029+
1030+
@Override
1031+
public Class<?>[] elementTypes() {
1032+
return new Class[]{Object.class};
1033+
}
1034+
})
9921035
);
9931036
}
9941037

src/main/java/ch/njol/skript/lang/util/common/AnyAmount.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
* @see AnyProvider
1111
*/
1212
@FunctionalInterface
13+
@Deprecated(since="INSERT VERSION")
1314
public interface AnyAmount extends AnyProvider {
1415

1516
/**

src/main/java/ch/njol/skript/lang/util/common/AnyContains.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
* @see AnyProvider
2020
*/
2121
@FunctionalInterface
22+
@Deprecated(since="INSERT VERSION")
2223
public interface AnyContains<Type> extends AnyProvider {
2324

2425
/**

src/main/java/ch/njol/skript/lang/util/common/AnyNamed.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
* @see AnyProvider
1111
*/
1212
@FunctionalInterface
13+
@Deprecated(since="INSERT VERSION")
1314
public interface AnyNamed extends AnyProvider {
1415

1516
/**

src/main/java/ch/njol/skript/lang/util/common/AnyProvider.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
* may conflict between things that provide two values (e.g. something declaring
2424
* both a name and a size)
2525
*/
26+
@Deprecated(since="INSERT VERSION")
2627
public interface AnyProvider {
2728

2829
}

src/main/java/ch/njol/skript/lang/util/common/AnyValued.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import ch.njol.skript.lang.ParseContext;
55
import ch.njol.skript.registrations.Classes;
66
import ch.njol.skript.util.StringMode;
7-
import com.sun.jdi.request.StepRequest;
87
import org.jetbrains.annotations.UnknownNullability;
98
import org.skriptlang.skript.lang.converter.Converters;
109

@@ -15,6 +14,7 @@
1514
*
1615
* @see AnyProvider
1716
*/
17+
@Deprecated(since="INSERT VERSION")
1818
public interface AnyValued<Type> extends AnyProvider {
1919

2020
/**

src/main/java/org/skriptlang/skript/lang/properties/PropCondContains.java

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import ch.njol.skript.lang.Expression;
66
import ch.njol.skript.lang.SkriptParser.ParseResult;
77
import ch.njol.skript.lang.util.SimpleExpression;
8+
import ch.njol.skript.registrations.Classes;
9+
import ch.njol.skript.util.LiteralUtils;
810
import ch.njol.util.Kleenean;
911
import org.bukkit.event.Event;
1012
import org.jetbrains.annotations.Nullable;
@@ -31,7 +33,6 @@ public class PropCondContains extends Condition {
3133

3234
@Override
3335
public boolean init(Expression<?>[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
34-
3536
this.haystack = PropertyUtils.asProperty(Property.CONTAINS, expressions[0]);
3637
if (haystack == null) {
3738
Skript.error("The expression " + expressions[0] + " returns types that do not contain anything.");
@@ -44,13 +45,35 @@ public boolean init(Expression<?>[] expressions, int matchedPattern, Kleenean is
4445
Skript.error("The expression " + haystack + " returns types that do not contain anything.");
4546
return false; // no name property found
4647
}
47-
// determine possible return types
48-
// elementTypes = getElementTypes(properties);
49-
this.needles = expressions[1];
48+
49+
this.needles = LiteralUtils.defendExpression(expressions[1]);
5050
explicitSingle = matchedPattern == 2 && parseResult.mark != 1 || haystack.isSingle();
5151

52-
needles = expressions[1];
53-
return true;
52+
if (explicitSingle) {
53+
// determine possible needle types
54+
Class<?>[][] elementTypes = getElementTypes(properties);
55+
var needleReturnTypes = needles.possibleReturnTypes();
56+
// if no needle types are compatible with the element types, error
57+
if (!determineTypeCompatibility(needleReturnTypes, elementTypes)) {
58+
Skript.error("'" + haystack + "' cannot contain " + Classes.toString(needleReturnTypes, false));
59+
return false;
60+
}
61+
}
62+
63+
return LiteralUtils.canInitSafely(haystack, needles);
64+
}
65+
66+
private static boolean determineTypeCompatibility(Class<?>[] needleReturnTypes, Class<?>[][] elementTypes) {
67+
for (Class<?> needleType : needleReturnTypes) {
68+
for (Class<?>[] haystackType : elementTypes) {
69+
for (Class<?> allowedNeedleType : haystackType) {
70+
if (allowedNeedleType.isAssignableFrom(needleType)) {
71+
return true;
72+
}
73+
}
74+
}
75+
}
76+
return false;
5477
}
5578

5679
private Class<?>[][] getElementTypes(PropertyMap<ContainsHandler<?, ?>> properties) {

src/main/java/org/skriptlang/skript/lang/properties/PropertyBaseExpression.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import ch.njol.skript.lang.ExpressionType;
88
import ch.njol.skript.lang.SkriptParser.ParseResult;
99
import ch.njol.skript.lang.util.SimpleExpression;
10+
import ch.njol.skript.util.LiteralUtils;
1011
import ch.njol.skript.util.Utils;
1112
import ch.njol.util.Kleenean;
1213
import org.bukkit.event.Event;
@@ -51,7 +52,7 @@ public boolean init(Expression<?>[] expressions, int matchedPattern, Kleenean is
5152
// determine possible return types
5253
returnTypes = getPropertyReturnTypes(properties, Handler::returnType);
5354
returnType = Utils.getSuperType(returnTypes);
54-
return true;
55+
return LiteralUtils.canInitSafely(expr);
5556
}
5657

5758
private Class<?> @NotNull [] getPropertyReturnTypes(@NotNull PropertyMap<Handler> properties, Function<Handler, Class<?>> getReturnType) {

src/main/java/org/skriptlang/skript/lang/properties/PropertyUtils.java

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import ch.njol.skript.classes.ClassInfo;
44
import ch.njol.skript.lang.Expression;
55
import ch.njol.skript.registrations.Classes;
6+
import ch.njol.skript.util.LiteralUtils;
67
import org.jetbrains.annotations.Nullable;
78

89
import java.util.HashMap;
@@ -55,11 +56,11 @@ public static Expression<?> asProperty(Property<?> property, Expression<?> expr)
5556
}
5657

5758
// get all types with a name property
58-
List<ClassInfo<?>> namedClassInfos = Classes.getClassInfosByProperty(property);
59-
Class<?>[] namedClasses = namedClassInfos.stream().map(ClassInfo::getC).toArray(Class[]::new);
59+
List<ClassInfo<?>> classInfos = Classes.getClassInfosByProperty(property);
60+
Class<?>[] classes = classInfos.stream().map(ClassInfo::getC).toArray(Class[]::new);
6061

6162
//noinspection unchecked,rawtypes
62-
return expr.getConvertedExpression((Class[]) namedClasses);
63+
return LiteralUtils.defendExpression(expr).getConvertedExpression((Class[]) classes);
6364
}
6465

6566

@@ -68,15 +69,35 @@ public static <Handler extends Property.PropertyHandler<?>> PropertyMap<Handler>
6869
Expression<?> expr
6970
) {
7071
PropertyMap<Handler> propertyInfos = new PropertyMap<>();
71-
// for each return type, check if it has a name property
72+
73+
// get all types with a name property
74+
List<ClassInfo<?>> classInfos = Classes.getClassInfosByProperty(property);
75+
76+
// for each return type, match to a classinfo w/ name property
7277
for (Class<?> returnType : expr.possibleReturnTypes()) {
73-
ClassInfo<?> classInfo = Classes.getSuperClassInfo(returnType);
74-
// get property
75-
var propertyInfo = classInfo.getPropertyInfo(property);
76-
if (propertyInfo == null) {
78+
ClassInfo<?> closestInfo = null;
79+
for (ClassInfo<?> propertiedClassInfo : classInfos) {
80+
if (propertiedClassInfo.getC() == returnType) {
81+
// exact match, use it
82+
closestInfo = propertiedClassInfo;
83+
break;
84+
}
85+
if (propertiedClassInfo.getC().isAssignableFrom(returnType)) {
86+
// closest match so far
87+
if (closestInfo == null || closestInfo.getC().isAssignableFrom(propertiedClassInfo.getC())) {
88+
closestInfo = propertiedClassInfo;
89+
}
90+
}
91+
}
92+
if (closestInfo == null) {
7793
continue; // no name property
7894
}
95+
96+
// get property
97+
var propertyInfo = closestInfo.getPropertyInfo(property);
98+
ClassInfo<?> classInfo = Classes.getSuperClassInfo(returnType);
7999
propertyInfos.put(classInfo.getC(), propertyInfo);
100+
propertyInfos.put(closestInfo.getC(), propertyInfo);
80101
}
81102
return propertyInfos;
82103
}

0 commit comments

Comments
 (0)