diff --git a/src/main/java/carpet/script/annotation/AnnotationParser.java b/src/main/java/carpet/script/annotation/AnnotationParser.java index 052cb524..7251ed75 100644 --- a/src/main/java/carpet/script/annotation/AnnotationParser.java +++ b/src/main/java/carpet/script/annotation/AnnotationParser.java @@ -20,7 +20,6 @@ import org.apache.commons.lang3.ClassUtils; import com.google.common.base.Suppliers; -import carpet.CarpetExtension; import carpet.script.Context; import carpet.script.Expression; import carpet.script.Fluff.AbstractLazyFunction; @@ -85,7 +84,7 @@ public final class AnnotationParser *

Parses a given {@link Class} and registers its annotated methods, the ones with the {@link ScarpetFunction} annotation, * to be used in the Scarpet language.

* - *

Only call this method once per class per lifetime of the JVM! (for example, at {@link CarpetExtension#onGameStarted()} or + *

Only call this method once per class per lifetime of the JVM! (for example, at {@link carpet.CarpetExtension#onGameStarted()} or * {@link ModInitializer#onInitialize()}).

* *

There is a set of requirements for the class and its methods:

diff --git a/src/main/java/carpet/script/annotation/ListConverter.java b/src/main/java/carpet/script/annotation/ListConverter.java index abdfbc5b..b2648ff8 100644 --- a/src/main/java/carpet/script/annotation/ListConverter.java +++ b/src/main/java/carpet/script/annotation/ListConverter.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import carpet.script.Context; import carpet.script.value.ListValue; import carpet.script.value.Value; @@ -32,17 +33,17 @@ final class ListConverter implements ValueConverter> } @Override - public List convert(final Value value) + public List convert(final Value value, final Context context) { - return value instanceof ListValue ? convertListValue((ListValue) value) : allowSingletonCreation ? convertSingleton(value) : null; + return value instanceof ListValue ? convertListValue((ListValue) value, context) : allowSingletonCreation ? convertSingleton(value, context) : null; } - private List convertListValue(final ListValue values) + private List convertListValue(final ListValue values, final Context context) { final List list = new ArrayList<>(values.getItems().size()); for (final Value value : values) { - final T converted = itemConverter.convert(value); + final T converted = itemConverter.convert(value, context); if (converted == null) { return null; @@ -52,9 +53,9 @@ final class ListConverter implements ValueConverter> return list; } - private List convertSingleton(final Value val) + private List convertSingleton(final Value val, final Context context) { - final T converted = itemConverter.convert(val); + final T converted = itemConverter.convert(val, context); if (converted == null) { return null; diff --git a/src/main/java/carpet/script/annotation/Locator.java b/src/main/java/carpet/script/annotation/Locator.java index 0c447c3e..daf403d6 100644 --- a/src/main/java/carpet/script/annotation/Locator.java +++ b/src/main/java/carpet/script/annotation/Locator.java @@ -276,7 +276,7 @@ public interface Locator private abstract static class AbstractLocator implements ValueConverter, Locator { @Override - public R convert(final Value value) + public R convert(final Value value, final Context context) { throw new UnsupportedOperationException("Cannot call a locator in a parameter that doesn't contain a context!"); } diff --git a/src/main/java/carpet/script/annotation/MapConverter.java b/src/main/java/carpet/script/annotation/MapConverter.java index a39671f5..e8ecda80 100644 --- a/src/main/java/carpet/script/annotation/MapConverter.java +++ b/src/main/java/carpet/script/annotation/MapConverter.java @@ -37,15 +37,15 @@ class MapConverter implements ValueConverter> } @Override - public Map convert(final Value value) + public Map convert(final Value value, final Context context) { final Map result = new HashMap<>(); if (value instanceof MapValue) { for (final Entry entry : ((MapValue) value).getMap().entrySet()) { - final K key = keyConverter.convert(entry.getKey()); - final V val = valueConverter.convert(entry.getValue()); + final K key = keyConverter.convert(entry.getKey(), context); + final V val = valueConverter.convert(entry.getValue(), context); if (key == null || val == null) { return null; @@ -105,14 +105,14 @@ class MapConverter implements ValueConverter> } @Override - public Map convert(final Value value) { - return value instanceof MapValue ? super.convert(value) - : value instanceof ListValue ? convertList(((ListValue)value).getItems()) + public Map convert(final Value value, final Context context) { + return value instanceof MapValue ? super.convert(value, context) + : value instanceof ListValue ? convertList(((ListValue)value).getItems(), context) : null; // Multiparam mode can only be used in evalAndConvert } - private Map convertList(final List valueList) + private Map convertList(final List valueList, final Context context) { if (valueList.size() % 2 == 1) { @@ -122,8 +122,8 @@ class MapConverter implements ValueConverter> final Iterator val = valueList.iterator(); while (val.hasNext()) { - final K key = keyConverter.convert(val.next()); - final V value = valueConverter.convert(val.next()); + final K key = keyConverter.convert(val.next(), context); + final V value = valueConverter.convert(val.next(), context); if (key == null || value == null) { return null; @@ -143,11 +143,11 @@ class MapConverter implements ValueConverter> final Value val = valueIterator.next(); if (!acceptMultiParam || val instanceof MapValue || (val instanceof ListValue && !(keyConverter instanceof ListConverter))) { - return convert(val); // @KeyValuePairs Map, Boolean> will not support list consumption + return convert(val, context); // @KeyValuePairs Map, Boolean> will not support list consumption } final Map map = new HashMap<>(); - K key = keyConverter.convert(val); //First pair is manual since we got it to check for a different conversion mode + K key = keyConverter.convert(val, context); //First pair is manual since we got it to check for a different conversion mode V value = valueConverter.checkAndConvert(valueIterator, context, theLazyT); if (key == null || value == null) { diff --git a/src/main/java/carpet/script/annotation/OptionalConverter.java b/src/main/java/carpet/script/annotation/OptionalConverter.java index 08519157..3ef26c3f 100644 --- a/src/main/java/carpet/script/annotation/OptionalConverter.java +++ b/src/main/java/carpet/script/annotation/OptionalConverter.java @@ -50,13 +50,13 @@ final class OptionalConverter implements ValueConverter> * {@link #checkAndConvert(Iterator, Context, Context.Type)} and is only used as a fallback in types that don't support it. */ @Override - public Optional convert(final Value value) + public Optional convert(final Value value, final Context context) { if (value.isNull()) { return Optional.empty(); } - final R converted = typeConverter.convert(value); + final R converted = typeConverter.convert(value, context); if (converted == null) { return null; diff --git a/src/main/java/carpet/script/annotation/OutputConverter.java b/src/main/java/carpet/script/annotation/OutputConverter.java index b7947618..737cbc78 100644 --- a/src/main/java/carpet/script/annotation/OutputConverter.java +++ b/src/main/java/carpet/script/annotation/OutputConverter.java @@ -6,7 +6,6 @@ import java.util.Objects; import java.util.function.Function; import net.minecraft.core.BlockPos; import net.minecraft.core.GlobalPos; -import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.nbt.Tag; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; diff --git a/src/main/java/carpet/script/annotation/Param.java b/src/main/java/carpet/script/annotation/Param.java index 7ec081cd..177b6faa 100644 --- a/src/main/java/carpet/script/annotation/Param.java +++ b/src/main/java/carpet/script/annotation/Param.java @@ -148,7 +148,7 @@ public interface Param @Override public String getTypeName() { return null; } @Override - public Context convert(final Value value) + public Context convert(final Value value, final Context context) { throw new UnsupportedOperationException("Called convert() with Value in Context Provider converter, where only checkAndConvert is supported"); } @@ -175,7 +175,7 @@ public interface Param @Override public String getTypeName() { return null; } @Override - public Context.Type convert(final Value value) + public Context.Type convert(final Value value, final Context context) { throw new UnsupportedOperationException("Called convert() with a Value in TheLazyT Provider, where only checkAndConvert is supported"); } diff --git a/src/main/java/carpet/script/annotation/SimpleTypeConverter.java b/src/main/java/carpet/script/annotation/SimpleTypeConverter.java index e6beccba..b5229071 100644 --- a/src/main/java/carpet/script/annotation/SimpleTypeConverter.java +++ b/src/main/java/carpet/script/annotation/SimpleTypeConverter.java @@ -2,12 +2,15 @@ package carpet.script.annotation; import java.util.HashMap; import java.util.Map; +import java.util.function.BiFunction; import java.util.function.Function; + +import carpet.script.CarpetContext; +import carpet.script.Context; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.Level; -import carpet.CarpetServer; import carpet.script.exception.InternalExpressionException; import carpet.script.value.EntityValue; import carpet.script.value.FormattedTextValue; @@ -31,9 +34,9 @@ public final class SimpleTypeConverter implements ValueConve private static final Map, SimpleTypeConverter> byResult = new HashMap<>(); static { - registerType(Value.class, ServerPlayer.class, val -> EntityValue.getPlayerByValue(CarpetServer.minecraft_server, val), "online player"); + registerType(Value.class, ServerPlayer.class, (v, c) -> EntityValue.getPlayerByValue(((CarpetContext)c).server(), v), "online player"); registerType(EntityValue.class, Entity.class, EntityValue::getEntity, "entity"); - registerType(Value.class, Level.class, val -> ValueConversions.dimFromValue(val, CarpetServer.minecraft_server), "dimension"); + registerType(Value.class, Level.class, (v, c) -> ValueConversions.dimFromValue(v, ((CarpetContext)c).server()), "dimension"); registerType(Value.class, Component.class, FormattedTextValue::getTextByValue, "text"); registerType(Value.class, String.class, Value::getString, "string"); // Check out @Param.Strict for more specific types @@ -44,7 +47,7 @@ public final class SimpleTypeConverter implements ValueConve registerType(Value.class, Boolean.class, Value::getBoolean, "boolean"); // Check out @Param.Strict for more specific types } - private final Function converter; + private final BiFunction converter; private final Class valueClass; private final String typeName; @@ -58,7 +61,7 @@ public final class SimpleTypeConverter implements ValueConve * @param inputType The required type for the input {@link Value} * @param converter The function to convert an instance of inputType into R. */ - public SimpleTypeConverter(final Class inputType, final Function converter, final String typeName) + public SimpleTypeConverter(final Class inputType, final BiFunction converter, final String typeName) { super(); this.converter = converter; @@ -66,6 +69,14 @@ public final class SimpleTypeConverter implements ValueConve this.typeName = typeName; } + public SimpleTypeConverter(final Class inputType, final Function converter, final String typeName) + { + super(); + this.converter = (v, c) -> converter.apply(v); + this.valueClass = inputType; + this.typeName = typeName; + } + @Override public String getTypeName() { @@ -87,9 +98,9 @@ public final class SimpleTypeConverter implements ValueConve @Override @SuppressWarnings("unchecked") // more than checked. not using class.cast because then "method is too big" for inlining, because javac is useless - public R convert(final Value value) // and adds millions of casts. This one is even removed + public R convert(final Value value, final Context context) // and adds millions of casts. This one is even removed { - return valueClass.isInstance(value) ? converter.apply((T)value) : null; + return valueClass.isInstance(value) ? converter.apply((T)value, context) : null; } /** @@ -99,15 +110,21 @@ public final class SimpleTypeConverter implements ValueConve * @param The type of the resulting object * @param requiredInputType The {@link Class} of {@code } * @param outputType The {@link Class} of {@code >} - * @param converter A function that converts from the given {@link Value} subtype to the given type. Should ideally return {@code null} + * @param converter A bi function that converts from the given {@link Value} subtype to the given type. Should ideally return {@code null} * when given {@link Value} cannot be converted to the {@code }, to follow the {@link ValueConverter} contract, but it * can also throw an {@link InternalExpressionException} by itself if really necessary. * @param typeName The name of the type, following the conventions of {@link ValueConverter#getTypeName()} */ public static void registerType(final Class requiredInputType, final Class outputType, - final Function converter, final String typeName) + final BiFunction converter, final String typeName) { final SimpleTypeConverter type = new SimpleTypeConverter<>(requiredInputType, converter, typeName); byResult.put(outputType, type); } + + public static void registerType(final Class requiredInputType, final Class outputType, + final Function converter, final String typeName) + { + registerType(requiredInputType, outputType, (val, ctx) -> converter.apply(val), typeName); + } } diff --git a/src/main/java/carpet/script/annotation/ValueCaster.java b/src/main/java/carpet/script/annotation/ValueCaster.java index cc8c01ce..fd422f40 100644 --- a/src/main/java/carpet/script/annotation/ValueCaster.java +++ b/src/main/java/carpet/script/annotation/ValueCaster.java @@ -3,6 +3,7 @@ package carpet.script.annotation; import java.util.HashMap; import java.util.Map; +import carpet.script.Context; import carpet.script.value.AbstractListValue; import carpet.script.value.BlockValue; import carpet.script.value.BooleanValue; @@ -79,7 +80,7 @@ public final class ValueCaster implements ValueConverter // R always exten @Override @SuppressWarnings("unchecked") // more than checked, see SimpleTypeConverter#converter for reasoning - public R convert(final Value value) + public R convert(final Value value, final Context context) { if (!outputType.isInstance(value)) { diff --git a/src/main/java/carpet/script/annotation/ValueConverter.java b/src/main/java/carpet/script/annotation/ValueConverter.java index ebf39148..c7de8977 100644 --- a/src/main/java/carpet/script/annotation/ValueConverter.java +++ b/src/main/java/carpet/script/annotation/ValueConverter.java @@ -50,6 +50,7 @@ public interface ValueConverter * trying to convert to anything else, where it would be recommended to tell the user the name of the final type instead.

* * @param value The {@link Value} to convert + * @param context * @return The converted value, or {@code null} if the conversion failed in the process * @apiNote

While most implementations of this method should and will return the type from this method, implementations that require * parameters from {@link #checkAndConvert(Iterator, Context, Context.Type)} or that require multiple parameters may decide to throw @@ -59,10 +60,16 @@ public interface ValueConverter *

Implementations can also provide different implementations for this and {@link #checkAndConvert(Iterator, Context, Context.Type)}, in case * they can support it in some situations that can't be used else, such as inside of lists or maps, although they should try to provide * in {@link #checkAndConvert(Iterator, Context, Context.Type)} at least the same conversion as the one from this method.

- *

Even with the above reasons, {@link ValueConverter} users should try to implement {@link #convert(Value)} whenever possible instead of + *

Even with the above reasons, {@link ValueConverter} users should try to implement {@link #convert(Value, Context)} whenever possible instead of * {@link #checkAndConvert(Iterator, Context, Context.Type)}, since it allows its usage in generics of lists and maps.

*/ - @Nullable R convert(Value value); + @Nullable R convert(Value value, final Context context); + + @Deprecated(forRemoval = true) + default R convert(final Value value) + { + return convert(value, null); + } /** *

Returns whether this {@link ValueConverter} consumes a variable number of elements from the {@link Iterator} passed to it via @@ -176,17 +183,17 @@ public interface ValueConverter * providers like {@link Context}.

Implementations can also use more than a single parameter when being called with this function, * but in such case they must implement {@link #valueConsumption()} to return how many parameters do they consume at minimum, and, if * they may consume variable arguments, implement {@link #consumesVariableArgs()}

This method holds the same nullability - * constraints as {@link #convert(Value)}

+ * constraints as {@link #convert(Value, Context)}

* @param valueIterator An {@link Iterator} holding the {@link Value} to convert in next position * @param context The {@link Context} this function has been called with. This was used when this passed lazy values instead in order to * evaluate, now it's used to get the context * @param contextType The {@link Context.Type} that the original function was called with * @return The next {@link Value} (s) converted to the type {@code } of this {@link ValueConverter} - * @implNote This method's default implementation runs the {@link #convert(Value)} function in the next {@link Value} ignoring {@link Context} and + * @implNote This method's default implementation runs the {@link #convert(Value, Context)} function in the next {@link Value} ignoring {@link Context} and * {@code theLazyT}. */ default R checkAndConvert(final Iterator valueIterator, final Context context, final Context.Type contextType) { - return !valueIterator.hasNext() ? null : convert(valueIterator.next()); + return !valueIterator.hasNext() ? null : convert(valueIterator.next(), context); } }