From a65d16c9ba7d74321d295105fbfc0dcdd5502cc7 Mon Sep 17 00:00:00 2001 From: gnembon Date: Wed, 21 Apr 2021 12:21:47 -0300 Subject: [PATCH] WIP unpacking of parameters. --- src/main/java/carpet/script/Context.java | 1 + src/main/java/carpet/script/Expression.java | 16 +++++---- src/main/java/carpet/script/Fluff.java | 34 ++++++++++++++++--- .../java/carpet/script/api/Auxiliary.java | 7 ++-- src/main/java/carpet/script/api/Entities.java | 4 +-- .../script/argument/FunctionArgument.java | 11 ++++++ .../carpet/script/language/Functions.java | 19 +++++++++-- .../carpet/script/language/Threading.java | 4 +-- .../value/FunctionUnpackedArgumentsValue.java | 10 ++++++ .../carpet/script/value/FunctionValue.java | 28 ++++++++++----- .../java/carpet/script/value/ListValue.java | 2 +- 11 files changed, 106 insertions(+), 30 deletions(-) create mode 100644 src/main/java/carpet/script/value/FunctionUnpackedArgumentsValue.java diff --git a/src/main/java/carpet/script/Context.java b/src/main/java/carpet/script/Context.java index fb9b583e..ad87fa17 100644 --- a/src/main/java/carpet/script/Context.java +++ b/src/main/java/carpet/script/Context.java @@ -19,6 +19,7 @@ public class Context public static final int LOCALIZATION = 8; public static final int LVALUE = 9; public static final int MAPDEF = 10; + public static final int CALLARGS = 11; public Map variables = new HashMap<>(); diff --git a/src/main/java/carpet/script/Expression.java b/src/main/java/carpet/script/Expression.java index d0c36074..51443de7 100644 --- a/src/main/java/carpet/script/Expression.java +++ b/src/main/java/carpet/script/Expression.java @@ -773,12 +773,16 @@ public class Expression stack.set(stack.size() - 1, stack.peek() - 2 + 1); break; case FUNCTION: - ILazyFunction f = functions.get(token.surface);// don't validate global - userdef functions - int numParams = stack.pop(); - if (f != null && !f.numParamsVaries() && numParams != f.getNumParams()) - { - throw new ExpressionException(c, this, token, "Function " + token + " expected " + f.getNumParams() + " parameters, got " + numParams); - } + //ILazyFunction f = functions.get(token.surface);// don't validate global - userdef functions + //int numParams = stack.pop(); + //if (f != null && !f.numParamsVaries() && numParams != f.getNumParams()) + //{ + // throw new ExpressionException(c, this, token, "Function " + token + " expected " + f.getNumParams() + " parameters, got " + numParams); + //} + stack.pop(); + // due to unpacking, all functions can have variable number of arguments + // we will be checking that at runtime. + // TODO try analyze arguments and assess if its possible that they are static if (stack.size() <= 0) { throw new ExpressionException(c, this, token, "Too many function calls, maximum scope exceeded"); diff --git a/src/main/java/carpet/script/Fluff.java b/src/main/java/carpet/script/Fluff.java index 9662f265..f492c830 100644 --- a/src/main/java/carpet/script/Fluff.java +++ b/src/main/java/carpet/script/Fluff.java @@ -1,6 +1,9 @@ package carpet.script; 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; @@ -85,6 +88,30 @@ public abstract class Fluff super(numParams); } + public static List unpackArgs(List lzargs, Context c) + { + List args = new ArrayList<>(); + for (LazyValue lv : lzargs) + { + Value arg = lv.evalValue(c, Context.CALLARGS); + if (arg instanceof FunctionUnpackedArgumentsValue) + { + args.addAll(((ListValue) arg).getItems()); + } + else + { + args.add(arg); + } + } + return args; + } + + public void checkArgs(int candidates) + { + if (!numParamsVaries() && getNumParams() !=candidates) + throw new InternalExpressionException("Function " + getName() + " expected " + getNumParams() + " parameters, got " + candidates); + } + @Override public LazyValue lazyEval(Context cc, Integer type, Expression e, Tokenizer.Token t, final List lazyParams) { @@ -100,10 +127,9 @@ public abstract class Fluff private List getParams(Context c) { if (params == null) { - params = new ArrayList<>(); - for (LazyValue lazyParam : lazyParams) { - params.add(lazyParam.evalValue(c)); // none type default by design - } + // very likely needs to be dynamic, so not static like here, or remember if it was. + params = unpackArgs(lazyParams, c); + checkArgs(params.size()); } return params; } diff --git a/src/main/java/carpet/script/api/Auxiliary.java b/src/main/java/carpet/script/api/Auxiliary.java index 76d73c31..9859bcb3 100644 --- a/src/main/java/carpet/script/api/Auxiliary.java +++ b/src/main/java/carpet/script/api/Auxiliary.java @@ -834,12 +834,13 @@ public class Auxiliary { throw new InternalExpressionException("'schedule' should have at least 2 arguments, delay and call name"); long delay = NumericValue.asNumber(lv.get(0).evalValue(c)).getLong(); - FunctionArgument functionArgument = FunctionArgument.findIn(c, expression.module, lv, 1, false, true); + FunctionArgument functionArgument = FunctionArgument.findIn(c, expression.module, lv, 1, false, false); + List args = functionArgument.unpackArgs(c); CarpetServer.scriptServer.events.scheduleCall( (CarpetContext) c, functionArgument.function, - FunctionValue.resolveArgs(functionArgument.args, c, t), + args, delay ); return (c_, t_) -> Value.TRUE; @@ -1043,7 +1044,7 @@ public class Auxiliary { } else { - success = host.getScriptServer().events.handleCustomEvent(event, host, callback.function, FunctionValue.resolveArgs(callback.args, c, t) )?Value.TRUE:Value.FALSE; + success = host.getScriptServer().events.handleCustomEvent(event, host, callback.function, callback.unpackArgs(c) )?Value.TRUE:Value.FALSE; } return (cc, tt) -> success; }); diff --git a/src/main/java/carpet/script/api/Entities.java b/src/main/java/carpet/script/api/Entities.java index 68a02904..ce2cd3b5 100644 --- a/src/main/java/carpet/script/api/Entities.java +++ b/src/main/java/carpet/script/api/Entities.java @@ -308,7 +308,7 @@ public class Entities { } else { - types.forEach(et -> events.addBuiltInEvent(CarpetEventServer.Event.getEntityLoadEventName(et), c.host, funArg.function, FunctionValue.resolveArgs(funArg.args, c, t))); + types.forEach(et -> events.addBuiltInEvent(CarpetEventServer.Event.getEntityLoadEventName(et), c.host, funArg.function, funArg.unpackArgs(c))); } Value ret = new NumericValue(types.size()); return (cc, tt) -> ret; @@ -326,7 +326,7 @@ public class Entities { FunctionArgument funArg = FunctionArgument.findIn(c, expression.module, lv, 2, true, false); - ((EntityValue) v).setEvent((CarpetContext)c, what, funArg.function, FunctionValue.resolveArgs(funArg.args, c, t)); + ((EntityValue) v).setEvent((CarpetContext)c, what, funArg.function, funArg.unpackArgs(c)); return LazyValue.NULL; }); diff --git a/src/main/java/carpet/script/argument/FunctionArgument.java b/src/main/java/carpet/script/argument/FunctionArgument.java index 8c52c8d5..ecd09034 100644 --- a/src/main/java/carpet/script/argument/FunctionArgument.java +++ b/src/main/java/carpet/script/argument/FunctionArgument.java @@ -1,6 +1,7 @@ package carpet.script.argument; import carpet.script.Context; +import carpet.script.Fluff; import carpet.script.LazyValue; import carpet.script.ScriptHost; import carpet.script.bundled.Module; @@ -94,4 +95,14 @@ public class FunctionArgument extends Argument return new FunctionArgument<>(function, 0, args); } + + public void checkArgs() { + function.checkArgs(args.size()); + } + + public List unpackArgs(Context c) { + List unpackedArgs = Fluff.AbstractFunction.unpackArgs((List) args, c); + function.checkArgs(unpackedArgs.size()); + return unpackedArgs; + } } diff --git a/src/main/java/carpet/script/language/Functions.java b/src/main/java/carpet/script/language/Functions.java index 1588a3e0..5c03dd13 100644 --- a/src/main/java/carpet/script/language/Functions.java +++ b/src/main/java/carpet/script/language/Functions.java @@ -6,12 +6,14 @@ import carpet.script.LazyValue; import carpet.script.argument.FunctionArgument; import carpet.script.exception.InternalExpressionException; import carpet.script.exception.ReturnStatement; +import carpet.script.value.AbstractListValue; import carpet.script.value.FunctionSignatureValue; import carpet.script.value.FunctionValue; import carpet.script.value.FunctionAnnotationValue; import carpet.script.value.ListValue; import carpet.script.value.StringValue; import carpet.script.value.Value; +import com.google.common.collect.ImmutableList; import java.util.ArrayList; import java.util.List; @@ -90,9 +92,20 @@ public class Functions { expression.addLazyUnaryOperator("...", Operators.precedence.get("def->..."), false, (c, t, lv) -> { - if (t != Context.LOCALIZATION) - throw new InternalExpressionException("That functionality has not been implemented yet."); - return (cc, tt) -> new FunctionAnnotationValue(lv.evalValue(c), 1); + if (t == Context.LOCALIZATION) + return (cc, tt) -> new FunctionAnnotationValue(lv.evalValue(c), 1); + if (t == Context.CALLARGS) + { + Value params = lv.evalValue(c, Context.NONE); + if (params instanceof ListValue) + return (cc, tt) -> params; + if (!(params instanceof AbstractListValue)) + throw new InternalExpressionException("Unable to unpack a non-list"); + Value unpacked = ListValue.wrap(ImmutableList.copyOf(((AbstractListValue) params).iterator())); + return (cc, tt) -> unpacked; + } + throw new InternalExpressionException("That functionality has not been implemented yet."); + }); //assigns const procedure to the lhs, returning its previous value diff --git a/src/main/java/carpet/script/language/Threading.java b/src/main/java/carpet/script/language/Threading.java index f3149ae6..f7dd0389 100644 --- a/src/main/java/carpet/script/language/Threading.java +++ b/src/main/java/carpet/script/language/Threading.java @@ -19,7 +19,7 @@ public class Threading if (lv.size() == 0) throw new InternalExpressionException("'task' requires at least function to call as a parameter"); FunctionArgument functionArgument = FunctionArgument.findIn(c, expression.module, lv, 0, false, true); - ThreadValue thread = new ThreadValue(Value.NULL, functionArgument.function, expr, tok, c, FunctionValue.resolveArgs(functionArgument.args, c, t)); + ThreadValue thread = new ThreadValue(Value.NULL, functionArgument.function, expr, tok, c, functionArgument.unpackArgs(c)); Thread.yield(); return (cc, tt) -> thread; }); @@ -30,7 +30,7 @@ public class Threading throw new InternalExpressionException("'task' requires at least function to call as a parameter"); Value queue = lv.get(0).evalValue(c); FunctionArgument functionArgument = FunctionArgument.findIn(c, expression.module, lv, 1, false, true); - ThreadValue thread = new ThreadValue(queue, functionArgument.function, expr, tok, c, FunctionValue.resolveArgs(functionArgument.args, c, t)); + ThreadValue thread = new ThreadValue(queue, functionArgument.function, expr, tok, c, functionArgument.unpackArgs(c)); Thread.yield(); return (cc, tt) -> thread; }); diff --git a/src/main/java/carpet/script/value/FunctionUnpackedArgumentsValue.java b/src/main/java/carpet/script/value/FunctionUnpackedArgumentsValue.java new file mode 100644 index 00000000..8c053e7b --- /dev/null +++ b/src/main/java/carpet/script/value/FunctionUnpackedArgumentsValue.java @@ -0,0 +1,10 @@ +package carpet.script.value; + +import java.util.List; + +public class FunctionUnpackedArgumentsValue extends ListValue +{ + public FunctionUnpackedArgumentsValue(List list) { + super(list); + } +} diff --git a/src/main/java/carpet/script/value/FunctionValue.java b/src/main/java/carpet/script/value/FunctionValue.java index 61e97b18..a05e87b1 100644 --- a/src/main/java/carpet/script/value/FunctionValue.java +++ b/src/main/java/carpet/script/value/FunctionValue.java @@ -11,7 +11,6 @@ import carpet.script.exception.ContinueStatement; import carpet.script.exception.ExpressionException; import carpet.script.exception.InternalExpressionException; import carpet.script.exception.ReturnStatement; -import carpet.script.exception.ThrowStatement; import net.minecraft.nbt.StringTag; import net.minecraft.nbt.Tag; @@ -173,15 +172,26 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction } } - @Override - public LazyValue lazyEval(Context c, Integer type, Expression e, Tokenizer.Token t, List lazyParams) + public void checkArgs(int candidates) { - assertArgsOk(lazyParams, (fixedArgs) ->{ + int actual = getArguments().size(); + + if (candidates < actual) + throw new InternalExpressionException("Function " + getPrettyString() + " requires at least " + actual + " arguments"); + if (candidates > actual && getVarArgs() == null) + throw new InternalExpressionException("Function " + getPrettyString() + " requires " + actual + " arguments"); + } + + @Override + public LazyValue lazyEval(Context c, Integer type, Expression e, Tokenizer.Token t, List lazyPrams) + { + List resolvedArgs = Fluff.AbstractFunction.unpackArgs(lazyPrams, c); + assertArgsOk(resolvedArgs, (fixedArgs) ->{ if (fixedArgs) // wrong number of args for fixed args { throw new ExpressionException(c, e, t, "Incorrect number of arguments for function "+name+ - ". Should be "+args.size()+", not "+lazyParams.size()+" like "+args + ". Should be "+args.size()+", not "+resolvedArgs.size()+" like "+args ); } else // too few args for varargs @@ -190,7 +200,7 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction argList.add("... "+varArgs); throw new ExpressionException(c, e, t, "Incorrect number of arguments for function "+name+ - ". Should be at least "+args.size()+", not "+lazyParams.size()+" like "+argList + ". Should be at least "+args.size()+", not "+resolvedArgs.size()+" like "+argList ); } }); @@ -200,15 +210,15 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction for (int i=0; i val); } if (varArgs != null) { List extraParams = new ArrayList<>(); - for (int i = args.size(), mx = lazyParams.size(); i < mx; i++) + for (int i = args.size(), mx = resolvedArgs.size(); i < mx; i++) { - extraParams.add(lazyParams.get(i).evalValue(c).reboundedTo(null)); // copy by value I guess + extraParams.add(resolvedArgs.get(i).reboundedTo(null)); // copy by value I guess } Value rest = ListValue.wrap(extraParams).bindTo(varArgs); // didn't we just copied that? newFrame.setVariable(varArgs, (cc, tt) -> rest); diff --git a/src/main/java/carpet/script/value/ListValue.java b/src/main/java/carpet/script/value/ListValue.java index de316668..7da9ee92 100644 --- a/src/main/java/carpet/script/value/ListValue.java +++ b/src/main/java/carpet/script/value/ListValue.java @@ -70,7 +70,7 @@ public class ListValue extends AbstractListValue implements ContainerValueInterf items.addAll(list); } - private ListValue(List list) + protected ListValue(List list) { items = list; }