Merge branch 'master' into 1.15

This commit is contained in:
gnembon committed 2019-11-18 01:17:37 -04:00
commit 12408cac75
17 files changed
+362 -220

No files matched your search

@@ -2,7 +2,7 @@ package carpet.fakes;
import carpet.script.CarpetContext;
import carpet.script.CarpetEventServer;
import carpet.script.ScriptHost;
import carpet.script.value.FunctionValue;
import carpet.script.value.Value;
import net.minecraft.entity.damage.DamageSource;
@@ -13,10 +13,10 @@ public interface EntityInterface
float getMainYaw(float partialTicks);
//scarpet part
void onDeathCallback(String reason);
void setDeathCallback(CarpetContext cc, String function, List<Value> extraArgs);
void setDeathCallback(CarpetContext cc, FunctionValue function, List<Value> extraArgs);
void onDamageCallback(float amount, DamageSource source);
void setDamageCallback(CarpetContext cc, String function, List<Value> extraArgs);
void setRemovedCallback(CarpetContext cc, String function, List<Value> extraArgs);
void setTickCallback(CarpetContext cc, String function, List<Value> extraArgs);
void setDamageCallback(CarpetContext cc, FunctionValue function, List<Value> extraArgs);
void setRemovedCallback(CarpetContext cc, FunctionValue function, List<Value> extraArgs);
void setTickCallback(CarpetContext cc, FunctionValue function, List<Value> extraArgs);
CarpetEventServer.ScheduledCall getTickCallback();
}
@@ -4,12 +4,10 @@ import carpet.CarpetServer;
import carpet.fakes.EntityInterface;
import carpet.script.CarpetContext;
import carpet.script.CarpetEventServer;
import carpet.script.ScriptHost;
import carpet.script.value.FunctionValue;
import carpet.script.value.Value;
import carpet.settings.CarpetSettings;
import net.minecraft.entity.Entity;
import net.minecraft.entity.damage.DamageSource;
import org.lwjgl.system.CallbackI;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
@@ -27,23 +25,20 @@ public abstract class Entity_scarpetEventsMixin implements EntityInterface
private CarpetEventServer.ScheduledCall tickCall;
private CarpetEventServer.ScheduledCall damageCall;
@Override
public void setDeathCallback(CarpetContext cc, String function, List<Value> extraArgs)
public void setDeathCallback(CarpetContext cc, FunctionValue function, List<Value> extraArgs)
{
deathCall = CarpetServer.scriptServer.events.makeDeathCall(cc, function, extraArgs);
}
@Override
public void setRemovedCallback(CarpetContext cc, String function, List<Value> extraArgs)
public void setRemovedCallback(CarpetContext cc, FunctionValue function, List<Value> extraArgs)
{
removeCall = CarpetServer.scriptServer.events.makeRemovedCall(cc, function, extraArgs);
}
@Override
public void setTickCallback(CarpetContext cc, String function, List<Value> extraArgs)
public void setTickCallback(CarpetContext cc, FunctionValue function, List<Value> extraArgs)
{
tickCall = CarpetServer.scriptServer.events.makeTickCall(cc, function, extraArgs);
}
@@ -55,7 +50,7 @@ public abstract class Entity_scarpetEventsMixin implements EntityInterface
}
@Override
public void setDamageCallback(CarpetContext cc, String function, List<Value> extraArgs)
public void setDamageCallback(CarpetContext cc, FunctionValue function, List<Value> extraArgs)
{
damageCall = CarpetServer.scriptServer.events.makeDamageCall(cc, function, extraArgs);
}
@@ -3,6 +3,7 @@ package carpet.script;
import carpet.CarpetServer;
import carpet.script.value.BlockValue;
import carpet.script.value.EntityValue;
import carpet.script.value.FunctionValue;
import carpet.script.value.ListValue;
import carpet.script.value.NumericValue;
import carpet.script.value.StringValue;
@@ -19,6 +20,7 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.dimension.DimensionType;
import org.apache.commons.lang3.tuple.Pair;
import java.util.ArrayList;
import java.util.Arrays;
@@ -39,9 +41,9 @@ public class CarpetEventServer
public static class Callback
{
public String host;
public String udf;
public FunctionValue udf;
public Callback(String host, String udf)
public Callback(String host, FunctionValue udf)
{
this.host = host;
this.udf = udf;
@@ -50,7 +52,7 @@ public class CarpetEventServer
@Override
public String toString()
{
return udf+((host==null)?"":"(from "+host+")");
return udf.getString()+((host==null)?"":"(from "+host+")");
}
}
@@ -61,7 +63,7 @@ public class CarpetEventServer
public BlockPos context_origin;
public long dueTime;
public ScheduledCall(CarpetContext context, String udf, List<LazyValue> args, long dueTime)
public ScheduledCall(CarpetContext context, FunctionValue udf, List<LazyValue> args, long dueTime)
{
super(context.host.getName(), udf);
this.args = args;
@@ -119,7 +121,7 @@ public class CarpetEventServer
// impossible call to add
return false;
}
UserDefinedFunction udf = host.globalFunctions.get(funName);
FunctionValue udf = host.globalFunctions.get(funName);
if (udf == null || udf.getArguments().size() != reqArgs)
{
// call won't match arguments
@@ -127,13 +129,13 @@ public class CarpetEventServer
}
//all clear
//remove duplicates
removeEventCall(hostName, funName);
callList.add(new Callback(hostName, funName));
removeEventCall(hostName, udf.getString());
callList.add(new Callback(hostName, udf));
return true;
}
public void removeEventCall(String hostName, String callName)
public void removeEventCall(String hostName, String funName)
{
callList.removeIf((c)-> c.udf.equalsIgnoreCase(callName) && ( hostName == null || c.host.equalsIgnoreCase(hostName) ) );
callList.removeIf((c)-> c.udf.getString().equals(funName) && ( hostName == null || c.host.equalsIgnoreCase(hostName) ) );
}
public void removeAllCalls(String hostName)
@@ -445,7 +447,7 @@ public class CarpetEventServer
}
}
public void scheduleCall(CarpetContext context, String function, List<LazyValue> args, long due)
public void scheduleCall(CarpetContext context, FunctionValue function, List<LazyValue> args, long due)
{
scheduledCalls.add(new ScheduledCall(context, function, args, due));
}
@@ -464,8 +466,8 @@ public class CarpetEventServer
if (!Event.byName.containsKey(event))
return false;
Callback callback= decodeCallback(funName);
Event.byName.get(event).handler.removeEventCall(callback.host, callback.udf);
Pair<String,String> call = decodeCallback(funName);
Event.byName.get(event).handler.removeEventCall(call.getLeft(), call.getRight());
return true;
}
@@ -474,21 +476,20 @@ public class CarpetEventServer
Event.byName.values().forEach((e) -> e.handler.removeAllCalls(hostName));
}
private Callback decodeCallback(String funName)
private Pair<String,String> decodeCallback(String funName)
{
Pattern find = Pattern.compile("(\\w+)\\(from (\\w+)\\)");
Matcher matcher = find.matcher(funName);
if(matcher.matches())
{
return new Callback(matcher.group(2), matcher.group(1));
return Pair.of(matcher.group(2), matcher.group(1));
}
return new Callback(null, funName);
return Pair.of(null, funName);
}
private ScheduledCall makeEventCall(CarpetContext cc, String function, List<Value> extraArgs, int argCount)
private ScheduledCall makeEventCall(CarpetContext cc, FunctionValue function, List<Value> extraArgs, int argCount)
{
UserDefinedFunction udf = cc.host.globalFunctions.get(function);
if (udf == null || (udf.getArguments().size()-(extraArgs == null ? 0 : extraArgs.size())) != argCount)
if (function == null || (function.getArguments().size()-(extraArgs == null ? 0 : extraArgs.size())) != argCount)
{
// call won't match arguments
return null;
@@ -503,19 +504,19 @@ public class CarpetEventServer
return new ScheduledCall(cc, function, lazyArgs, 0);
}
public ScheduledCall makeDeathCall(CarpetContext cc, String function, List<Value> extraArgs)
public ScheduledCall makeDeathCall(CarpetContext cc, FunctionValue function, List<Value> extraArgs)
{
return makeEventCall(cc, function, extraArgs, 2);
}
public ScheduledCall makeRemovedCall(CarpetContext cc, String function, List<Value> extraArgs)
public ScheduledCall makeRemovedCall(CarpetContext cc, FunctionValue function, List<Value> extraArgs)
{
return makeEventCall(cc, function, extraArgs, 1);
}
public ScheduledCall makeTickCall(CarpetContext cc, String function, List<Value> extraArgs)
public ScheduledCall makeTickCall(CarpetContext cc, FunctionValue function, List<Value> extraArgs)
{
return makeEventCall(cc, function, extraArgs, 1);
}
public ScheduledCall makeDamageCall(CarpetContext cc, String function, List<Value> extraArgs)
public ScheduledCall makeDamageCall(CarpetContext cc, FunctionValue function, List<Value> extraArgs)
{
return makeEventCall(cc, function, extraArgs, 4);
}
@@ -6,10 +6,12 @@ import carpet.fakes.BiomeArrayInterface;
import carpet.helpers.FeatureGenerator;
import carpet.script.Fluff.TriFunction;
import carpet.script.exception.CarpetExpressionException;
import carpet.script.exception.ExitStatement;
import carpet.script.exception.ExpressionException;
import carpet.script.exception.InternalExpressionException;
import carpet.script.value.BlockValue;
import carpet.script.value.EntityValue;
import carpet.script.value.FunctionValue;
import carpet.script.value.LazyListValue;
import carpet.script.value.ListValue;
import carpet.script.value.NBTSerializableValue;
@@ -2023,9 +2025,16 @@ public class CarpetExpression
throw new InternalExpressionException("First argument to entity_event should be an entity");
String what = lv.get(1).evalValue(c).getString();
Value functionValue = lv.get(2).evalValue(c);
String function = null;
if (!(functionValue instanceof NullValue))
function = functionValue.getString();
if (functionValue instanceof NullValue)
functionValue = null;
else if (!(functionValue instanceof FunctionValue))
{
String name = functionValue.getString();
functionValue = c.host.globalFunctions.get(name);
if (functionValue == null)
throw new InternalExpressionException("Function "+name+" is not defined yet");
}
FunctionValue function = (FunctionValue)functionValue;
List<Value> args = null;
if (lv.size()==4)
args = Collections.singletonList(lv.get(3).evalValue(c));
@@ -2939,7 +2948,7 @@ public class CarpetExpression
CarpetServer.scriptServer.tickStart = System.nanoTime(); // for the next tick
Thread.yield();
if(CarpetServer.scriptServer.stopAll)
throw new Expression.ExitStatement(Value.NULL);
throw new ExitStatement(Value.NULL);
return (cc, tt) -> Value.TRUE;
});
@@ -3013,20 +3022,28 @@ public class CarpetExpression
if (lv.size()<2)
throw new InternalExpressionException("'schedule' should have at least 2 arguments, delay and call name");
Long delay = NumericValue.asNumber(lv.get(0).evalValue(c)).getLong();
String funname = lv.get(1).evalValue(c).getString();
Value functionValue = lv.get(1).evalValue(c);
if (!(functionValue instanceof FunctionValue))
{
String name = functionValue.getString();
functionValue = c.host.globalFunctions.get(name);
if (functionValue == null)
throw new InternalExpressionException("Function "+name+" is not defined yet");
}
FunctionValue function = (FunctionValue)functionValue;
CarpetContext cc = (CarpetContext)c;
if (!cc.host.globalFunctions.containsKey(funname))
throw new InternalExpressionException("Function "+funname+" is not defined");
List<LazyValue> args = new ArrayList<>();
for (int i=2; i < lv.size(); i++)
{
Value arg = lv.get(i).evalValue(cc);
args.add( (_c, _t) -> arg);
}
if (cc.host.globalFunctions.get(funname).getArguments().size() != args.size())
throw new InternalExpressionException("Function "+funname+" takes "+
cc.host.globalFunctions.get(funname).getArguments().size()+" arguments, "+args.size()+" provided.");
CarpetServer.scriptServer.events.scheduleCall(cc, funname, args, delay);
if (function.getArguments().size() != args.size())
throw new InternalExpressionException("Function "+function.getString()+" takes "+
function.getArguments().size()+" arguments, "+args.size()+" provided.");
CarpetServer.scriptServer.events.scheduleCall(cc, function, args, delay);
return (c_, t_) -> Value.TRUE;
});
@@ -1,6 +1,7 @@
package carpet.script;
import carpet.script.bundled.BundledModule;
import carpet.script.value.FunctionValue;
import carpet.script.value.MapValue;
import carpet.script.value.StringValue;
import carpet.settings.CarpetSettings;
@@ -365,19 +366,19 @@ public class CarpetScriptServer
return true;
}
public boolean runas(ServerCommandSource source, String hostname, String udf_name, List<LazyValue> argv)
public boolean runas(ServerCommandSource source, String hostname, FunctionValue udf, List<LazyValue> argv)
{
return runas(BlockPos.ORIGIN, source, hostname, udf_name, argv);
return runas(BlockPos.ORIGIN, source, hostname, udf, argv);
}
public boolean runas(BlockPos origin, ServerCommandSource source, String hostname, String udf_name, List<LazyValue> argv)
public boolean runas(BlockPos origin, ServerCommandSource source, String hostname, FunctionValue udf, List<LazyValue> argv)
{
ScriptHost host = globalHost;
try
{
if (hostname != null)
host = modules.get(hostname).retrieveForExecution(source);
host.callUDF(origin, source, host.globalFunctions.get(udf_name), argv);
host.callUDF(origin, source, udf, argv);
}
catch (NullPointerException | InvalidCallbackException npe)
{
+1 -1
View File
@@ -37,7 +37,7 @@ public class Context
return host.globalVariables.get(name);
}
void setVariable(String name, LazyValue lv)
public void setVariable(String name, LazyValue lv)
{
if (name.startsWith("global_"))
{
+24 -119
View File
@@ -11,11 +11,15 @@ import carpet.script.Fluff.QuadFunction;
import carpet.script.Fluff.QuinnFunction;
import carpet.script.Fluff.SexFunction;
import carpet.script.Fluff.TriFunction;
import carpet.script.exception.ExitStatement;
import carpet.script.exception.ExpressionException;
import carpet.script.exception.InternalExpressionException;
import carpet.script.exception.ReturnStatement;
import carpet.script.exception.ThrowStatement;
import carpet.script.value.AbstractListValue;
import carpet.script.value.ContainerValueInterface;
import carpet.script.value.FunctionSignatureValue;
import carpet.script.value.FunctionValue;
import carpet.script.value.GlobalValue;
import carpet.script.value.LContainerValue;
import carpet.script.value.LazyListValue;
@@ -389,31 +393,6 @@ public class Expression implements Cloneable
return copy;
}
/* Exception thrown to terminate execution mid expression (aka return statement) */
static class ExitStatement extends RuntimeException
{
Value retval;
ExitStatement(Value value)
{
retval = value;
}
}
static class ReturnStatement extends ExitStatement
{
ReturnStatement(Value value)
{
super(value);
}
}
static class ThrowStatement extends ExitStatement
{
ThrowStatement(Value value)
{
super(value);
}
}
static List<String> getExpressionSnippet(Tokenizer.Token token, Expression expr)
{
@@ -679,22 +658,11 @@ public class Expression implements Cloneable
}
});
}
private void addContextFunction(Context context, String name, Expression expr, Tokenizer.Token token, List<String> arguments, List<String> globals, LazyValue code)
private FunctionValue addContextFunction(Context context, String name, Expression expr, Tokenizer.Token token, List<String> arguments, List<String> globals, LazyValue code)
{
name = name.toLowerCase(Locale.ROOT);
if (functions.containsKey(name))
throw new ExpressionException(expr, token, "Function "+name+" would mask a built-in function");
Expression function_context;
try
{
function_context = expr.clone();
function_context.name = name;
}
catch (CloneNotSupportedException e)
{
throw new ExpressionException(expr, token, "Problems in allocating global function "+name);
}
Map<String, LazyValue> contextValues = new HashMap<>();
for (String global : globals)
{
@@ -708,67 +676,12 @@ public class Expression implements Cloneable
contextValues.put(global, lv);
}
}
if (contextValues.isEmpty()) contextValues = null;
context.host.globalFunctions.put(name, new UserDefinedFunction(arguments, function_context, token)
{
@Override
public LazyValue lazyEval(Context c, Integer type, Expression e, Tokenizer.Token t, List<LazyValue> lazyParams)
{
if (arguments.size() != lazyParams.size()) // something that might be subject to change in the future
{
throw new ExpressionException(e, t,
"Incorrect number of arguments for function "+name+
". Should be "+arguments.size()+", not "+lazyParams.size()+" like "+arguments
);
}
Context newFrame = c.recreate();
contextValues.forEach(newFrame::setVariable);
for (int i=0; i<arguments.size(); i++)
{
String arg = arguments.get(i);
Value val = lazyParams.get(i).evalValue(c).reboundedTo(arg);
newFrame.setVariable(arg, (cc, tt) -> val);
}
Value retVal;
boolean rethrow = false;
try
{
retVal = code.evalValue(newFrame, type); // todo not sure if we need to propagete type / consider boolean context in defined functions - answer seems ye
}
catch (ReturnStatement returnStatement)
{
retVal = returnStatement.retval;
}
catch (ThrowStatement throwStatement) // might not be really necessary
{
retVal = throwStatement.retval;
rethrow = true;
}
catch (InternalExpressionException exc)
{
throw new ExpressionException(function_context, t, exc.getMessage());
}
catch (ArithmeticException exc)
{
throw new ExpressionException(function_context, t, "Your math is wrong, "+exc.getMessage());
}
catch (ExitStatement | ExpressionException exit)
{
throw exit;
}
catch (Exception exc)
{
throw new ExpressionException(e, t, "Error while evaluating expression: "+exc.getMessage());
}
if (rethrow)
{
throw new ThrowStatement(retVal);
}
Value otherRetVal = retVal;
return (cc, tt) -> otherRetVal;
}
});
FunctionValue result = new FunctionValue(expr, token, name, code, arguments, contextValues);
// do not store lambda definitions
if (!name.equals("_")) context.host.globalFunctions.put(name, result);
return result;
}
/**
@@ -944,25 +857,28 @@ public class Expression implements Cloneable
addLazyFunctionWithDelegation("call",-1, (c, t, expr, tok, lv) -> { // adjust based on c
if (lv.size() == 0)
throw new InternalExpressionException("'call' expects at least function name to call");
String name = lv.get(0).evalValue(c).getString();
//lv.remove(lv.size()-1); // aint gonna cut it // maybe it will because of the eager eval changes
if (t != Context.SIGNATURE) // just call the function
{
if (!c.host.globalFunctions.containsKey(name))
Value functionValue = lv.get(0).evalValue(c);
if (!(functionValue instanceof FunctionValue))
{
throw new InternalExpressionException("Function "+name+" is not defined yet");
String name = functionValue.getString();
functionValue = c.host.globalFunctions.get(name);
if (functionValue == null)
throw new InternalExpressionException("Function "+name+" is not defined yet");
}
List<LazyValue> lvargs = new ArrayList<>(lv.size()-1);
for (int i=1; i< lv.size(); i++)
{
lvargs.add(lv.get(i));
}
UserDefinedFunction acf = c.host.globalFunctions.get(name);
Value retval = acf.lazyEval(c, t, acf.expression, acf.token, lvargs).evalValue(c);
FunctionValue fun = (FunctionValue)functionValue;
Value retval = fun.callInContext(expr, c, t, fun.getExpression(), fun.getToken(), lvargs).evalValue(c);
return (cc, tt) -> retval; ///!!!! dono might need to store expr and token in statics? (e? t?)
}
// gimme signature
String name = lv.get(0).evalValue(c).getString();
List<String> args = new ArrayList<>();
List<String> globals = new ArrayList<>();
for (int i = 1; i < lv.size(); i++)
@@ -981,8 +897,6 @@ public class Expression implements Cloneable
args.add(v.boundVariable);
}
}
if (name.equals("_"))
name = "__lambda_"+tok.lineno+"_"+tok.linepos;
Value retval = new FunctionSignatureValue(name, args, globals);
return (cc, tt) -> retval;
});
@@ -1003,20 +917,11 @@ public class Expression implements Cloneable
addLazyBinaryOperatorWithDelegation("->", precedence.get("def->"), false, (c, type, e, t, lv1, lv2) ->
{
Value v1 = lv1.evalValue(c, Context.SIGNATURE);
String result;
if (v1 instanceof FunctionSignatureValue)
{
FunctionSignatureValue sign = (FunctionSignatureValue) v1;
addContextFunction(c, sign.getName(), e, t, sign.getArgs(), sign.getGlobals(), lv2);
result = sign.getName();
}
else
{
v1.assertAssignable();
c.setVariable(v1.getVariable(), lv2);
result = v1.getVariable();
}
return (cc, tt) -> new StringValue(result);
if (!(v1 instanceof FunctionSignatureValue))
throw new InternalExpressionException("'->' operator requires a function signature on the LHS");
FunctionSignatureValue sign = (FunctionSignatureValue) v1;
Value result = addContextFunction(c, sign.getName(), e, t, sign.getArgs(), sign.getGlobals(), lv2);
return (cc, tt) -> result;
});
addFunction("exit", (lv) -> { throw new ExitStatement(lv.size()==0?Value.NULL:lv.get(0)); });
@@ -1,6 +1,6 @@
package carpet.script;
import carpet.CarpetServer;
import carpet.script.exception.ExpressionException;
import org.apache.commons.lang3.StringUtils;
import java.util.Collections;
@@ -26,6 +26,20 @@ public class ExpressionInspector
return e.getName();
}
public static Expression Expression_cloneWithName(Expression e, String name, Tokenizer.Token token)
{
Expression copy = null;
try
{
copy = e.clone();
}
catch (CloneNotSupportedException ex)
{
throw new ExpressionException(e, token, "Problems in allocating global function "+name);
}
return copy.withName(name);
}
private static TreeSet<String> scarpetFunctions;
private static TreeSet<String> APIFunctions;
static
+9 -11
View File
@@ -2,6 +2,7 @@ package carpet.script;
import carpet.CarpetServer;
import carpet.script.bundled.ModuleInterface;
import carpet.script.value.FunctionValue;
import carpet.settings.CarpetSettings;
import carpet.script.exception.ExpressionException;
import carpet.script.exception.InvalidCallbackException;
@@ -20,7 +21,6 @@ import net.minecraft.util.math.BlockPos;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -31,7 +31,7 @@ import static java.lang.Math.max;
public class ScriptHost
{
private final Map<String, ScriptHost> userHosts = new Object2ObjectOpenHashMap<>();
public Map<String, UserDefinedFunction> globalFunctions = new Object2ObjectOpenHashMap<>();
public Map<String, FunctionValue> globalFunctions = new Object2ObjectOpenHashMap<>();
public Map<String, LazyValue> globalVariables = new Object2ObjectOpenHashMap<>();
private Tag globalState;
@@ -118,8 +118,8 @@ public class ScriptHost
{
if (CarpetServer.scriptServer.stopAll)
return "SCARPET PAUSED";
UserDefinedFunction acf = globalFunctions.get(call);
if (acf == null)
FunctionValue function = globalFunctions.get(call);
if (function == null)
return "UNDEFINED";
List<LazyValue> argv = new ArrayList<>();
if (coords != null)
@@ -185,7 +185,7 @@ public class ScriptHost
return "Fail: "+tok.surface+" is not allowed in invoke";
}
}
List<String> args = acf.getArguments();
List<String> args = function.getArguments();
if (argv.size() != args.size())
{
String error = "Fail: stored function "+call+" takes "+args.size()+" arguments, not "+argv.size()+ ":\n";
@@ -200,7 +200,7 @@ public class ScriptHost
// TODO: this is just for now - invoke would be able to invoke other hosts scripts
Context context = new CarpetContext(this, source, BlockPos.ORIGIN);
return Expression.evalValue(
() -> acf.lazyEval(context, Context.VOID, acf.expression, acf.token, argv),
() -> function.lazyEval(context, Context.VOID, function.getExpression(), function.getToken(), argv),
context,
Context.VOID
).getString();
@@ -211,13 +211,11 @@ public class ScriptHost
}
}
public Value callUDF(BlockPos pos, ServerCommandSource source, UserDefinedFunction acf, List<LazyValue> argv) throws InvalidCallbackException
public Value callUDF(BlockPos pos, ServerCommandSource source, FunctionValue fun, List<LazyValue> argv) throws InvalidCallbackException
{
if (CarpetServer.scriptServer.stopAll)
return Value.NULL;
List<String> args = acf.getArguments();
if (argv.size() != args.size())
if (argv.size() != fun.getArguments().size())
{
throw new InvalidCallbackException();
}
@@ -226,7 +224,7 @@ public class ScriptHost
// TODO: this is just for now - invoke would be able to invoke other hosts scripts
Context context = new CarpetContext(this, source, pos);
return Expression.evalValue(
() -> acf.lazyEval(context, Context.VOID, acf.expression, acf.token, argv),
() -> fun.lazyEval(context, Context.VOID, fun.getExpression(), fun.getToken(), argv),
context,
Context.VOID);
}
@@ -1,29 +0,0 @@
package carpet.script;
import java.util.List;
public abstract class UserDefinedFunction extends Fluff.AbstractLazyFunction implements Fluff.ILazyFunction
{
protected List<String> arguments;
protected Expression expression;
protected Tokenizer.Token token;
UserDefinedFunction(List<String> args, Expression expr, Tokenizer.Token t)
{
super(args.size());
arguments = args;
expression = expr;
token = t;
}
public List<String> getArguments()
{
return arguments;
}
public Expression getExpression()
{
return expression;
}
public Tokenizer.Token getToken()
{
return token;
}
}
@@ -0,0 +1,13 @@
package carpet.script.exception;
import carpet.script.value.Value;
/* Exception thrown to terminate execution mid expression (aka return statement) */
public class ExitStatement extends RuntimeException
{
public Value retval;
public ExitStatement(Value value)
{
retval = value;
}
}
@@ -0,0 +1,12 @@
package carpet.script.exception;
import carpet.script.value.Value;
public class ReturnStatement extends ExitStatement
{
public ReturnStatement(Value value)
{
super(value);
}
}
@@ -0,0 +1,11 @@
package carpet.script.exception;
import carpet.script.value.Value;
public class ThrowStatement extends ExitStatement
{
public ThrowStatement(Value value)
{
super(value);
}
}
@@ -775,14 +775,14 @@ public class EntityValue extends Value
// "nbt" <-big one, for now use run('data merge entity ...
}};
public void setEvent(CarpetContext cc, String event, String fun, List<Value> args)
public void setEvent(CarpetContext cc, String event, FunctionValue fun, List<Value> args)
{
if (!(events.containsKey(event)))
throw new InternalExpressionException("Unknown entity event: " + event);
events.get(event).accept(cc, entity, fun, args);
}
private static Map<String, Fluff.QuadConsumer<CarpetContext, Entity, String, List<Value>>> events = new HashMap<String, Fluff.QuadConsumer<CarpetContext, Entity, String, List<Value>>>() {{
private static Map<String, Fluff.QuadConsumer<CarpetContext, Entity, FunctionValue, List<Value>>> events = new HashMap<String, Fluff.QuadConsumer<CarpetContext, Entity, FunctionValue, List<Value>>>() {{
put("on_death", (c, e, f, l) -> ((EntityInterface)e).setDeathCallback(c, f, l));
put("on_removed", (c, e, f, l) -> ((EntityInterface)e).setRemovedCallback(c, f, l));
put("on_tick", (c, e, f, l) -> ((EntityInterface)e).setTickCallback(c, f, l));
@@ -1,7 +1,5 @@
package carpet.script.value;
import carpet.script.exception.ExpressionException;
import java.util.List;
public class FunctionSignatureValue extends FrameworkValue
@@ -10,7 +8,6 @@ public class FunctionSignatureValue extends FrameworkValue
private List<String> arguments;
private List<String> globals;
public FunctionSignatureValue(String name, List<String> args, List<String> globals)
{
this.identifier = name;
@@ -0,0 +1,204 @@
package carpet.script.value;
import carpet.script.Context;
import carpet.script.Expression;
import carpet.script.ExpressionInspector;
import carpet.script.Fluff;
import carpet.script.LazyValue;
import carpet.script.Tokenizer;
import carpet.script.exception.ExitStatement;
import carpet.script.exception.ExpressionException;
import carpet.script.exception.InternalExpressionException;
import carpet.script.exception.ReturnStatement;
import carpet.script.exception.ThrowStatement;
import java.util.List;
import java.util.Map;
public class FunctionValue extends Value implements Fluff.ILazyFunction
{
private Expression expression;
private Tokenizer.Token token;
private String name;
private LazyValue body;
private Map<String, LazyValue> outerState;
private List<String> args;
private static long variantCounter = 1;
private long variant;
public FunctionValue(Expression expression, Tokenizer.Token token, String name, LazyValue body, List<String> args)
{
this.expression = expression;
this.token = token;
this.name = name;
this.body = body;
this.args = args;
this.outerState = null;
variant = 0L;
}
public FunctionValue(Expression expression, Tokenizer.Token token, String name, LazyValue body, List<String> args, Map<String, LazyValue> outerState)
{
this.expression = expression;
this.token = token;
this.name = name;
this.body = body;
this.args = args;
this.outerState = outerState;
variant = variantCounter++;
}
@Override
public String getString()
{
return name;
}
@Override
public boolean getBoolean()
{
return true;
}
@Override
protected Value clone()
{
FunctionValue ret = new FunctionValue(expression, token, name, body, args);
ret.outerState = this.outerState;
ret.variant = this.variant;
return ret;
}
@Override
public int hashCode()
{
return name.hashCode()+(int)variant;
}
@Override
public boolean equals(Object o)
{
if (o instanceof FunctionValue)
return name.equals(((FunctionValue) o).name) && variant == ((FunctionValue) o).variant;
return false;
}
@Override
public int compareTo(final Value o)
{
if (o instanceof FunctionValue)
{
int nameSame = this.name.compareTo(((FunctionValue) o).name);
if (nameSame != 0)
return nameSame;
return (int) (variant-((FunctionValue) o).variant);
}
return getString().compareTo(o.getString());
}
@Override
public double readNumber()
{
throw new InternalExpressionException("Function value has no numeric value");
}
@Override
public Value slice(long from, long to)
{
throw new InternalExpressionException("Cannot slice a function");
}
@Override
public int getNumParams()
{
return args.size();
}
@Override
public boolean numParamsVaries()
{
return false;
}
public LazyValue callInContext(Expression callingExpression, Context c, Integer type, Expression e, Tokenizer.Token t, List<LazyValue> lazyParams)
{
// this hole thing might not be really needed
Expression callContext = ExpressionInspector.Expression_cloneWithName(callingExpression, name, t);
try
{
return lazyEval(c, type, e, t, lazyParams);
}
catch (InternalExpressionException exc)
{
throw new ExpressionException(callContext, t, exc.getMessage());
}
catch (ArithmeticException exc)
{
throw new ExpressionException(callContext, t, "Your math is wrong, "+exc.getMessage());
}
}
@Override
public LazyValue lazyEval(Context c, Integer type, Expression e, Tokenizer.Token t, List<LazyValue> lazyParams)
{
if (args.size() != lazyParams.size()) // something that might be subject to change in the future
// in case we add variable arguments
{
throw new ExpressionException(e, t,
"Incorrect number of arguments for function "+name+
". Should be "+args.size()+", not "+lazyParams.size()+" like "+args
);
}
Context newFrame = c.recreate();
if (outerState != null) outerState.forEach(newFrame::setVariable);
for (int i=0; i<args.size(); i++)
{
String arg = args.get(i);
Value val = lazyParams.get(i).evalValue(c).reboundedTo(arg);
newFrame.setVariable(arg, (cc, tt) -> val);
}
Value retVal;
boolean rethrow = false;
try
{
retVal = body.evalValue(newFrame, type); // todo not sure if we need to propagete type / consider boolean context in defined functions - answer seems ye
}
catch (ReturnStatement returnStatement)
{
retVal = returnStatement.retval;
}
catch (ThrowStatement throwStatement) // might not be really necessary
{
retVal = throwStatement.retval;
rethrow = true;
}
catch (ArithmeticException | ExitStatement | ExpressionException exc)
{
throw exc; // rethrow so could be contextualized if needed
}
catch (Exception exc)
{
throw new ExpressionException(e, t, "Error while evaluating expression: "+exc.getMessage());
}
if (rethrow)
{
throw new ThrowStatement(retVal);
}
Value otherRetVal = retVal;
return (cc, tt) -> otherRetVal;
}
public Expression getExpression()
{
return expression;
}
public Tokenizer.Token getToken()
{
return token;
}
public List<String> getArguments()
{
return args;
}
}
@@ -3,6 +3,7 @@ package carpet.settings;
import carpet.CarpetServer;
import carpet.utils.Messenger;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
@@ -264,8 +265,10 @@ public class SettingsManager
String lcSearch = search.toLowerCase(Locale.ROOT);
return rules.values().stream().filter(rule ->
{
if (rule.name.toLowerCase(Locale.ROOT).contains(lcSearch)) return true;
for (String c : rule.categories) if (c.toLowerCase(Locale.ROOT).equals(search)) return true;
if (rule.name.toLowerCase(Locale.ROOT).contains(lcSearch)) return true; // substring match, case insensitive
for (String c : rule.categories) if (c.equals(search)) return true; // category exactly, case sensitive
if (Sets.newHashSet(rule.description.toLowerCase(Locale.ROOT).split("\\W+")).contains(lcSearch))
return true; // contains full term in description, but case insensitive
return false;
}).collect(ImmutableList.toImmutableList());
}