Files
fabric-carpet/src/main/java/carpet/script/Fluff.java
T
altrisi cc7a9c01be 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
2021-05-21 01:33:00 -03:00

286 lines
8.7 KiB
Java

package carpet.script;
import carpet.CarpetSettings;
import carpet.script.exception.ExpressionException;
import carpet.script.exception.InternalExpressionException;
import carpet.script.value.FunctionUnpackedArgumentsValue;
import carpet.script.value.ListValue;
import carpet.script.value.Value;
import java.util.ArrayList;
import java.util.List;
public abstract class Fluff
{
@FunctionalInterface
public interface TriFunction<A, B, C, R> { R apply(A a, B b, C c); }
@FunctionalInterface
public interface TriConsumer<A, B, C> { void accept(A a, B b, C c); }
@FunctionalInterface
public interface QuadConsumer<A, B, C, D> { void accept(A a, B b, C c, D d); }
@FunctionalInterface
public interface QuadFunction<A, B, C, D, R> { R apply(A a, B b, C c, D d);}
@FunctionalInterface
public interface QuinnFunction<A, B, C, D, E, R> { R apply(A a, B b, C c, D d, E e);}
@FunctionalInterface
public interface SexFunction<A, B, C, D, E, F, R> { R apply(A a, B b, C c, D d, E e, F f);}
public interface EvalNode
{
/**
* @return true if function has constant output if arguments are constant and can be evaluated
* statically (without context)
*/
boolean pure();
/**
* @return true if function has constant output if arguments are constant and can be evaluated
* statically (without context)
*/
boolean transitive();
/**
* @return required argument eval type in case its evaluated statically without context but with a given context type
*/
default Context.Type staticType(Context.Type outerType) {return transitive()?outerType:Context.NONE;};
}
public interface ILazyFunction extends EvalNode
{
int getNumParams();
boolean numParamsVaries();
LazyValue lazyEval(Context c, Context.Type type, Expression expr, Tokenizer.Token token, List<LazyValue> lazyParams);
static void checkInterrupts()
{
if (ScriptHost.mainThread != Thread.currentThread() && Thread.currentThread().isInterrupted())
throw new InternalExpressionException("Thread interrupted");
}
// lazy function has a chance to change execution based on contxt
}
public interface IFunction extends ILazyFunction
{
Value eval(List<Value> parameters);
}
public interface ILazyOperator extends EvalNode
{
int getPrecedence();
boolean isLeftAssoc();
LazyValue lazyEval(Context c, Context.Type type, Expression e, Tokenizer.Token t, LazyValue v1, LazyValue v2);
}
public interface IOperator extends ILazyOperator
{
Value eval(Value v1, Value v2);
}
public abstract static class AbstractLazyFunction implements ILazyFunction
{
protected String name;
int numParams;
public AbstractLazyFunction(int numParams, String name)
{
this.numParams = numParams;
this.name = name;
}
public String getName() {
return name;
}
public int getNumParams() {
return numParams;
}
public boolean numParamsVaries() {
return numParams < 0;
}
public static List<Value> unpackLazy(List<LazyValue> lzargs, Context c, Context.Type contextType)
{
List<Value> args = new ArrayList<>();
for (LazyValue lv : lzargs)
{
Value arg = lv.evalValue(c, contextType);
if (arg instanceof FunctionUnpackedArgumentsValue)
args.addAll(((ListValue) arg).getItems());
else
args.add(arg);
}
return args;
}
public List<Value> unpackArgs(List<LazyValue> lzargs, Context c, Context.Type contextType)
{
List<Value> args = unpackLazy(lzargs, c, contextType);
if (!numParamsVaries() && getNumParams() != args.size())
throw new InternalExpressionException("Function " + getName() + " expected " + getNumParams() + " parameters, got " + args.size());
return args;
}
public static List<LazyValue> lazify(List<Value> args)
{
List<LazyValue> lzargs = new ArrayList<>(args.size());
args.forEach( v -> lzargs.add( (c, t) -> v));
return lzargs;
}
}
public abstract static class AbstractFunction extends AbstractLazyFunction implements IFunction
{
AbstractFunction(int numParams, String name) {
super(numParams, name);
}
@Override
public boolean pure() {
return true;
}
@Override
public boolean transitive() {
return false;
}
@Override
public LazyValue lazyEval(Context cc, Context.Type type, Expression e, Tokenizer.Token t, final List<LazyValue> lazyParams)
{
return new LazyValue()
{ // eager evaluation always ignores the required type and evals params by none default
private List<Value> params;
public Value evalValue(Context c, Context.Type type)
{
ILazyFunction.checkInterrupts();
try
{
return AbstractFunction.this.eval(getParams(c));
}
catch (RuntimeException exc)
{
throw Expression.handleCodeException(cc, exc, e, t);
}
}
private List<Value> getParams(Context c)
{
if (params == null)
{
// very likely needs to be dynamic, so not static like here, or remember if it was.
params = unpackArgs(lazyParams, c, Context.Type.NONE);
}
else
{
CarpetSettings.LOG.error("How did we get here 1");
}
return params;
}
};
}
}
public abstract static class AbstractLazyOperator implements ILazyOperator
{
int precedence;
boolean leftAssoc;
AbstractLazyOperator(int precedence, boolean leftAssoc) {
this.precedence = precedence;
this.leftAssoc = leftAssoc;
}
public int getPrecedence() {
return precedence;
}
public boolean isLeftAssoc() {
return leftAssoc;
}
}
public abstract static class AbstractOperator extends AbstractLazyOperator implements IOperator
{
AbstractOperator(int precedence, boolean leftAssoc) {
super(precedence, leftAssoc);
}
@Override
public boolean pure() {
return true;
}
@Override
public boolean transitive() {
return false;
}
@Override
public LazyValue lazyEval(Context cc, Context.Type type, Expression e, Tokenizer.Token t, final LazyValue v1, final LazyValue v2)
{
try
{
return (c, type_ignored) -> AbstractOperator.this.eval(v1.evalValue(c, Context.Type.NONE), v2.evalValue(c, Context.Type.NONE));
}
catch (RuntimeException exc)
{
throw Expression.handleCodeException(cc, exc, e, t);
}
}
}
public abstract static class AbstractUnaryOperator extends AbstractOperator
{
AbstractUnaryOperator(int precedence, boolean leftAssoc) {
super(precedence, leftAssoc);
}
@Override
public boolean pure() {
return true;
}
@Override
public boolean transitive() {
return false;
}
@Override
public LazyValue lazyEval(Context cc, Context.Type type, Expression e, Tokenizer.Token t, final LazyValue v1, final LazyValue v2)
{
try
{
if (v2 != null)
{
throw new ExpressionException(cc, e, t, "Did not expect a second parameter for unary operator");
}
return (c, ignored_type) -> AbstractUnaryOperator.this.evalUnary(v1.evalValue(c, Context.Type.NONE));
}
catch (RuntimeException exc)
{
throw Expression.handleCodeException(cc, exc, e, t);
}
}
@Override
public Value eval(Value v1, Value v2)
{
throw new RuntimeException("Shouldn't end up here");
}
public abstract Value evalUnary(Value v1);
}
}