Annotated Scarpet (#772)

* Progress by now.

* Output conversions plus a few extra random things

* More progress, mostly list converting and a way to get converters

* Apply ValueConverters, refactor valueconverter getter to

accept types with annotations and generics, made listconverter pass
those params and annotations recursively. And probably more things.

* Some extra docs, the 100% most important thing

* Added MapConverter, strict Strings and Texts, some docs additions

and commented out heuristics

* Rework StrictParam to use SimpleTypeConverters and be saved in a map

* Minor changes and docs & added non-fully-functional context "converter"

* Added support for variable value count converters, multi-value eaters &

0 value eaters (Context).

* Docs update, enable Context converter, fix minor TODOs

* Move (most) parameter annotations into a single class,

remove deprecated ValueCaster#cast, update some docs.

* Small refactor of Param.Strict registering, added boolean to it

* Added PairConverter, moved Context and LV ValueConverters to Params

* Document public methods of AnnotationParser

* Add a lot more docs, make it ready for the first preview PR

* Move ValueConverter population outside of makeFunction,

check lv size for > max arguments, minor doc updates and workaround for
Mercury#28 until released

* Added optional parameters (declared using Java's Optional),

made evalAndConvert check for the presence of the next iteration,
updated test class

* Generalize Value OutputConverter

* ListConverter and MapConverter now follow ValueConverter contract of

incorrect value handling, returning a complete null for an incorrect
value anywhere. Also small fix to OptionalConverter and docs.
Getting ready for checking null in AnnotationParser!

* Change reflection's #invoke to a MethodHandle to boost speed by a lot

Commented

* Dedupe code, update and remove outdated todos, add 2 new ValueCasters

* Merge lambdas in display_title2 test function to be more accurate

* Check nulls somehow, I guess

* Move base function logic into a class to stop

passing hundreds of parameters into static functions and therefore simplify it

* Reduce visibility and fix a bug with PairConverter

* Hide Context provider in usage report

* Add support for primitive varargs

* Added TheLazyT converter

* Drop #getPrefixedTypeName and use 'something' as name of values

* Use value again because of varargs, document that

* Remove a completed TODO

* Remove old disabled heuristic value type name getter

* Fix TheLazyT

* Preparing locators before touching current Carpet infrastructure

* Add notes about non-implementedness of remaining locators

* Added APIs to register custom ValueConverters

* Mention new APIs in javadocs

* Adapt to new Carpet changes and deprecated non-implemented annotations

* Update example function for display_title()

* Better implementation for player_list example

* Fix example error message

* FunctionArgument no longer has generics

* Modernize Text converters

* OutputConverter is final, plus other small changes

* Few non-behavioural changes

* Rename LazyFunction to ScarpetFunction

* Drop LazyValue in parameters, not in return

Updating docs was a nightmare

* CARPET CHANGE - Make Fluff.AbstractLazyFunction.unpackArgs call unpackLazy (was duped)

* Make errors more like current Scarpet errors

* Allow customizing ContextType when evaluating arguments

* Add a few missing docs, comment out outdated ValueCaster doc

It's been a while, wow

* Fix for new Carpet signature :irritatered:

Please don't break API methods! Extensions may be using them, and they
will just crash the game or behave in unexpected ways else!

* Format all code to Carpet's. Powered by Eclipse

Reviewed to be sure it's ok. No functional changes, except from a small correction

* Always use full name for Context.Type

* Add parsing for all current Scarpet api and language classes

And remove test functions

* Allow void return type

* Fix no param methods

Whoops!

* Remove outdated comment and fix small javadoc linting problem

* Drop Param.TheLazyT in favour of just Context.Type type

And small performance improvement to varargs varargs since fastutil's toArray is crap

* Quote functions in error messages

* Make SimpleTypeConverter independent of ValueCaster

'Real world' usage demonstrated it can be annoying else, mostly for wrapper only values where you just want the wrapped object
This commit is contained in:
altrisi authored and GitHub committed 2021-05-21 01:33:00 -03:00
1 parent 7fd49e0f04
commit cc7a9c01be
16 files changed
+1976 -9

No files matched your search

@@ -0,0 +1,129 @@
package carpet.script.annotation;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import org.apache.commons.lang3.ClassUtils;
import carpet.script.LazyValue;
import carpet.script.value.EntityValue;
import carpet.script.value.FormattedTextValue;
import carpet.script.value.NBTSerializableValue;
import carpet.script.value.NumericValue;
import carpet.script.value.StringValue;
import carpet.script.value.Value;
import carpet.script.value.ValueConversions;
import net.minecraft.entity.Entity;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.Tag;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import net.minecraft.util.dynamic.GlobalPos;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
/**
* <p>A converter from a given {@link Object} of type T into a {@link LazyValue}, used in order to convert the outputs of methods into usable Scarpet
* values.</p>
*
* @see #register(Class, Function)
* @see #registerToValue(Class, Function)
* @param <T> The type to convert from into a {@link LazyValue}
*/
public final class OutputConverter<T>
{
private static final Map<Class<?>, OutputConverter<?>> byResult = new HashMap<>();
private static final OutputConverter<Value> VALUE = new OutputConverter<>(v -> (c, t) -> v);
static
{
register(LazyValue.class, Function.identity()); // Primitives are handled. Things are boxed in the process anyway, therefore
register(Boolean.class, v -> (v ? LazyValue.TRUE : LazyValue.FALSE)); // would recommend boxed outputs, so you can use null
register(Void.TYPE, v -> LazyValue.NULL);
registerToValue(Integer.class, NumericValue::of);
registerToValue(Double.class, NumericValue::of);
registerToValue(Float.class, NumericValue::of);
registerToValue(Long.class, NumericValue::of);
registerToValue(String.class, StringValue::new);
registerToValue(Entity.class, EntityValue::new);
registerToValue(Text.class, FormattedTextValue::new);
registerToValue(Tag.class, NBTSerializableValue::new);
registerToValue(BlockPos.class, ValueConversions::of);
registerToValue(Vec3d.class, ValueConversions::of);
registerToValue(ItemStack.class, ValueConversions::of);
registerToValue(Identifier.class, ValueConversions::of);
registerToValue(GlobalPos.class, ValueConversions::of);
}
private final Function<T, LazyValue> converter;
private OutputConverter(Function<T, LazyValue> converter)
{
this.converter = converter;
}
/**
* <p>Returns the {@link OutputConverter} for the specified returnType.</p>
*
* @param <T> The type of the {@link OutputConverter} you are looking for
* @param returnType The class that the returned {@link OutputConverter} converts from
* @return The {@link OutputConverter} for the specified returnType
*/
@SuppressWarnings("unchecked") // OutputConverters are stored with their class, for sure since the map is private (&& class has same generic as
// converter)
public static <T> OutputConverter<T> get(Class<T> returnType)
{
if (Value.class.isAssignableFrom(returnType))
return (OutputConverter<T>) VALUE;
returnType = (Class<T>) ClassUtils.primitiveToWrapper(returnType); // wrapper holds same generic as primitive: wrapped
return (OutputConverter<T>) Objects.requireNonNull(byResult.get(returnType),
"Unregistered output type: " + returnType + ". Register in OutputConverter");
}
/**
* <p>Converts the given input object into a {@link LazyValue}, to be used in return values of Scarpet functions</p>
*
* <p>Returns {@link LazyValue#NULL} if passed a {@code null} input</p>
*
* @param input The value to convert
* @return The converted value
*/
public LazyValue convert(T input)
{
return input == null ? LazyValue.NULL : converter.apply(input);
}
/**
* <p>Registers a new type to be able to be used as the return value of methods, converting from inputType to a {@link LazyValue}.</p>
*
* @see #registerToValue(Class, Function)
* @param <T> The type of the input type
* @param inputType The class of T
* @param converter The function that converts the an instance of T to a {@link LazyValue}
*/
public static <T> void register(Class<T> inputType, Function<T, LazyValue> converter)
{
OutputConverter<T> instance = new OutputConverter<T>(converter);
if (byResult.containsKey(inputType))
throw new IllegalArgumentException(inputType + " already has a registered OutputConverter");
byResult.put(inputType, instance);
}
/**
* <p>Registers a new type to be able to be used as the return value of methods, converting from inputType to a {@link LazyValue}, with the
* converter returning a {@link Value} type.</p>
*
* @see #register(Class, Function)
* @param <T> The type of the input type
* @param inputType The class of T
* @param converter The function that converts an instance of T to a {@link Value}
*/
public static <T> void registerToValue(Class<T> inputType, Function<T, Value> converter)
{
OutputConverter<T> instance = new OutputConverter<>(converter.andThen(v -> (c, t) -> v));
if (byResult.containsKey(inputType))
throw new IllegalArgumentException(inputType + " already has a registered OutputConverter");
byResult.put(inputType, instance);
}
}