This class parses methods annotated with the {@link ScarpetFunction} annotation in a given {@link Class}, generating
* fully-featured, automatically parsed and converted functions to be used in the Scarpet language.
*
*
This class and the rest in this package will try to ensure that the annotated method receives the proper parameters
* directly, without all the always-repeated code of evaluating {@link Value}s, checking and casting them to their respective
* types, and converting them to the final needed object.
*
*
To do that, functions will save a list of {@link ValueConverter}s to convert all their parameters. {@link ValueConverter}s
* are able to convert from any compatible {@link Value} instance into the requested parameter type, as long as they are registered
* using their respective {@code register} functions.
*
*
Built-in {@link ValueConverter}s include but are not limited to converters to convert {@link List}s to actual Java lists while also
* converting every item inside of the {@link List} to the specified generic parameter ({@code <>}), with the same applying for maps
*
*
Parameters can be given the annotations (present in the {@link Locator} and {@link Param} interfaces) in order to restrict them or
* make them more permissive to accept types, such as {@link Param.AllowSingleton} for lists.
*
*
You can also declare optional parameters by using Java's {@link Optional} as the type of one of your parameters, though it must be
* at the end of the function, just before varargs if present and/or any other {@link Optional} parameters.
*
*
Output of the annotated methods will also be converted to a compatible {@link LazyValue} using the registered {@link OutputConverter}s,
* allowing to remove the need of explicitly converting to a {@link Value} and then to a {@link LazyValue} just to end the method (though you can
* return a {@link LazyValue} if you want.
*
*
For a variable argument count, the Java varargs notation can be used in the last parameter, converting the function into a variable argument
* function that will pass all the rest of parameters to that last varargs parameter, also converted into the specified type.
*
*
To begin, use the {@link #parseFunctionClass(Class)} method in a class with methods annotated with the {@link ScarpetFunction} annotation.
*
* @see ScarpetFunction
* @see Locator.Block
* @see Locator.Vec3d
* @see Param.Strict
* @see Param.AllowSingleton
* @see Param.KeyValuePairs
* @see Param.Custom
* @see Optional
* @see OutputConverter#registerToValue(Class, java.util.function.Function)
* @see OutputConverter#register(Class, java.util.function.Function)
* @see ValueCaster#register(Class, String)
* @see SimpleTypeConverter#registerType(Class, Class, java.util.function.Function, String)
* @see Param.Params#registerStrictConverter(Class, boolean, ValueConverter)
* @see Param.Params#registerCustomConverterFactory(java.util.function.BiFunction)
*/
public final class AnnotationParser
{
static final int UNDEFINED_PARAMS = -2;
private static final List functionList = new ArrayList<>();
/**
*
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
* {@link ModInitializer#onInitialize()}).
*
*
There is a set of requirements for the class and its methods:
*
*
Annotated methods must not throw checked exceptions. They can throw regular {@link RuntimeException}s (including but not limited to
* {@link InternalExpressionException}).
* Basically, it's fine as long as you don't add a {@code throws} declaration to your methods.
*
Varargs (or effectively varargs) annotated methods must explicitly declare a maximum number of parameters to ingest in the {@link ScarpetFunction}
* annotation. They can still declare an unlimited amount by setting that maximum to {@link ScarpetFunction#UNLIMITED_PARAMS}. "Effectively varargs"
* means a function that has at least a parameter requiring a {@link ValueConverter} that has declared {@link ValueConverter#consumesVariableArgs()}.
*
Annotated methods must not have a parameter with generics as the varargs parameter. This is just because it was painful for me (altrisi) and
* didn't want to support it. Those will crash with a {@code ClassCastException}
*
*
Additionally, if the class contains annotated instance (non-static) methods, the class must be concrete and provide a no-arg constructor
* to instantiate it.
*
* @see ScarpetFunction
* @param clazz The class to parse
*/
public static void parseFunctionClass(Class> clazz)
{
// Only try to instantiate or require concrete classes if there are non-static annotated methods
Supplier