modules and imports

This commit is contained in:
gnembon committed 2020-01-08 23:38:31 -04:00
1 parent 34bf877bc7
commit 4f65be946c
17 files changed
+467 -302

No files matched your search

@@ -37,6 +37,7 @@ import java.util.Locale;
import java.util.concurrent.CompletableFuture;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import static net.minecraft.server.command.CommandManager.argument;
import static net.minecraft.server.command.CommandManager.literal;
@@ -78,7 +79,7 @@ public class ScriptCommand
executes( (cc) -> { CarpetServer.scriptServer.stopAll = false; return 1;});
LiteralArgumentBuilder<ServerCommandSource> l = literal("run").
requires((player) -> player.hasPermissionLevel(2)).
then(argument("expr", StringArgumentType.greedyString()).suggests((cc, bb) -> suggestCode(cc, bb)).
then(argument("expr", StringArgumentType.greedyString()).suggests(ScriptCommand::suggestCode).
executes((cc) -> compute(
cc,
StringArgumentType.getString(cc, "expr"))));
@@ -141,7 +142,7 @@ public class ScriptCommand
then(argument("from", BlockPosArgumentType.blockPos()).
then(argument("to", BlockPosArgumentType.blockPos()).
then(argument("expr", StringArgumentType.greedyString()).
suggests((cc, bb) -> suggestCode(cc, bb)).
suggests(ScriptCommand::suggestCode).
executes( (cc) -> scriptScan(
cc,
BlockPosArgumentType.getBlockPos(cc, "origin"),
@@ -288,7 +289,7 @@ public class ScriptCommand
private static Collection<String> suggestFunctionCalls(CommandContext<ServerCommandSource> c)
{
CarpetScriptHost host = getHost(c);
return host.getPublicFunctions();
return host.globaFunctionNames(host.myCode, s -> !s.startsWith("_")).sorted().collect(Collectors.toList());
}
private static int listEvents(ServerCommandSource source)
{
@@ -314,9 +315,8 @@ public class ScriptCommand
ServerCommandSource source = context.getSource();
Messenger.m(source, "lb Stored functions"+((host == CarpetServer.scriptServer.globalHost)?":":" in "+host.getName()+":"));
for (String fname : host.getAvailableFunctions(all))
{
FunctionValue fun = host.globalFunctions.get(fname);
host.globaFunctionNames(host.myCode, (str) -> all || !str.startsWith("__")).sorted().forEach( (s) -> {
FunctionValue fun = host.getFunction(s);
Expression expr = fun.getExpression();
Tokenizer.Token tok = fun.getToken();
List<String> snippet = ExpressionInspector.Expression_getExpressionSnippet(tok, expr);
@@ -326,16 +326,13 @@ public class ScriptCommand
Messenger.m(source, "w "+snippetLine);
}
Messenger.m(source, "gi ----------------");
}
});
//Messenger.m(source, "w "+code);
Messenger.m(source, "w ");
Messenger.m(source, "lb Global variables"+((host == CarpetServer.scriptServer.globalHost)?":":" in "+host.getName()+":"));
for (String vname : host.globalVariables.keySet())
{
if (!vname.startsWith("global")) continue;
Messenger.m(source, "wb "+vname+": ", "w "+ host.globalVariables.get(vname).evalValue(null).getPrettyString());
}
host.globaVariableNames(host.myCode, (s) -> s.startsWith("global_")).sorted().forEach( (s) -> {
Messenger.m(source, "wb "+s+": ", "w "+ host.getGlobalVariable(s).evalValue(null).getPrettyString());
});
return 1;
}
@@ -402,7 +399,7 @@ public class ScriptCommand
ServerCommandSource source = context.getSource();
CarpetScriptHost host = getHost(context);
handleCall(source, host, () -> {
CarpetExpression ex = new CarpetExpression(expr, source, new BlockPos(0, 0, 0));
CarpetExpression ex = new CarpetExpression(host.myCode, expr, source, new BlockPos(0, 0, 0));
return ex.scriptRunCommand(host, new BlockPos(source.getPosition()));
});
return 1;
@@ -413,7 +410,8 @@ public class ScriptCommand
ServerCommandSource source = context.getSource();
CarpetScriptHost host = getHost(context);
MutableIntBoundingBox area = new MutableIntBoundingBox(a, b);
CarpetExpression cexpr = new CarpetExpression(expr, source, origin);
CarpetExpression cexpr = new CarpetExpression(host.myCode, expr, source, origin);
int int_1 = area.getBlockCountX() * area.getBlockCountY() * area.getBlockCountZ();
if (int_1 > CarpetSettings.fillLimit)
{
@@ -463,7 +461,7 @@ public class ScriptCommand
ServerCommandSource source = context.getSource();
CarpetScriptHost host = getHost(context);
MutableIntBoundingBox area = new MutableIntBoundingBox(a, b);
CarpetExpression cexpr = new CarpetExpression(expr, source, origin);
CarpetExpression cexpr = new CarpetExpression(host.myCode, expr, source, origin);
int int_1 = area.getBlockCountX() * area.getBlockCountY() * area.getBlockCountZ();
if (int_1 > CarpetSettings.fillLimit)
{
+10 -1
View File
@@ -1,5 +1,6 @@
package carpet.script;
import carpet.script.value.Value;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.util.math.BlockPos;
@@ -15,9 +16,17 @@ public class CarpetContext extends Context
}
@Override
public Context recreate()
public Context duplicate()
{
return new CarpetContext(this.host, this.s, this.origin);
}
@Override
protected void initialize()
{
super.initialize();
variables.put("_x", (c, t) -> Value.ZERO);
variables.put("_y", (c, t) -> Value.ZERO);
variables.put("_z", (c, t) -> Value.ZERO);
}
}
@@ -130,7 +130,7 @@ public class CarpetEventServer
// impossible call to add
return false;
}
FunctionValue udf = host.globalFunctions.get(funName);
FunctionValue udf = host.getFunction(funName);
if (udf == null || udf.getArguments().size() != reqArgs)
{
// call won't match arguments
@@ -7,6 +7,7 @@ import carpet.helpers.FeatureGenerator;
import carpet.mixins.ChunkTicketManager_scarpetMixin;
import carpet.mixins.ServerChunkManager_scarpetMixin;
import carpet.script.Fluff.TriFunction;
import carpet.script.bundled.Module;
import carpet.script.exception.CarpetExpressionException;
import carpet.script.exception.ExitStatement;
import carpet.script.exception.ExpressionException;
@@ -2135,9 +2136,7 @@ public class CarpetExpression
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 = c.host.getAssertFunction(this.expr.module, name);
}
FunctionValue function = (FunctionValue)functionValue;
List<Value> args = null;
@@ -3194,9 +3193,7 @@ public class CarpetExpression
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 = c.host.getAssertFunction(this.expr.module, name);
}
FunctionValue function = (FunctionValue)functionValue;
@@ -3298,11 +3295,13 @@ public class CarpetExpression
* @param source source
* @param origin origin
*/
public CarpetExpression(String expression, ServerCommandSource source, BlockPos origin)
public CarpetExpression(Module module, String expression, ServerCommandSource source, BlockPos origin)
{
this.origin = origin;
this.source = source;
this.expr = new Expression(expression);
this.expr.asAModule(module);
API_BlockManipulation();
API_EntityManipulation();
@@ -1,7 +1,7 @@
package carpet.script;
import carpet.CarpetServer;
import carpet.script.bundled.ModuleInterface;
import carpet.script.bundled.Module;
import carpet.script.exception.CarpetExpressionException;
import carpet.script.exception.ExpressionException;
import carpet.script.exception.InternalExpressionException;
@@ -36,7 +36,7 @@ public class CarpetScriptHost extends ScriptHost
private Tag globalState;
private int saveTimeout;
private CarpetScriptHost(CarpetScriptServer server, ModuleInterface code, boolean perUser, ScriptHost parent)
private CarpetScriptHost(CarpetScriptServer server, Module code, boolean perUser, ScriptHost parent)
{
super(code, perUser, parent);
this.saveTimeout = 0;
@@ -45,12 +45,9 @@ public class CarpetScriptHost extends ScriptHost
globalState = loadState();
}
public static CarpetScriptHost create(CarpetScriptServer scriptServer, ModuleInterface module, boolean perPlayer, ServerCommandSource source)
public static CarpetScriptHost create(CarpetScriptServer scriptServer, Module module, boolean perPlayer, ServerCommandSource source)
{
CarpetScriptHost host = new CarpetScriptHost(scriptServer, module, perPlayer, null );
host.globalVariables.put("_x", (c, t) -> Value.ZERO);
host.globalVariables.put("_y", (c, t) -> Value.ZERO);
host.globalVariables.put("_z", (c, t) -> Value.ZERO);
// parse code and convert to expression
if (module != null)
{
@@ -63,8 +60,8 @@ public class CarpetScriptHost extends ScriptHost
return null;
}
host.setChatErrorSnooper(source);
CarpetExpression ex = new CarpetExpression(code, source, new BlockPos(0, 0, 0));
ex.getExpr().asAModule(module);
CarpetExpression ex = new CarpetExpression(host.myCode, code, source, new BlockPos(0, 0, 0));
ex.getExpr().asATextSource();
ex.scriptRunCommand(host, new BlockPos(source.getPosition()));
}
catch (CarpetExpressionException e)
@@ -85,11 +82,11 @@ public class CarpetScriptHost extends ScriptHost
}
@Override
public void addUserDefinedFunction(String funName, FunctionValue function)
public void addUserDefinedFunction(Module module, String funName, FunctionValue function)
{
super.addUserDefinedFunction(funName, function);
super.addUserDefinedFunction(module, funName, function);
// mcarpet
if (funName.startsWith("__on_"))
if (funName.startsWith("__on_")) // here we can make a determination if we want to only accept events from main module.
{
// this is nasty, we have the host and function, yet we add it via names, but hey - works for now
String event = funName.replaceFirst("__on_","");
@@ -99,35 +96,27 @@ public class CarpetScriptHost extends ScriptHost
}
@Override
protected ModuleInterface getModuleByName(String name)
protected Module getModuleByName(String name)
{
ModuleInterface module = scriptServer.getModule(name);
Module module = scriptServer.getModule(name);
if (module == null || module.getCode() == null)
throw new InternalExpressionException("Unable to locate package: "+name);
return module;
}
@Override
protected boolean runModuleCode(Context c, ModuleInterface module)
protected void runModuleCode(Context c, Module module)
{
CarpetContext cc = (CarpetContext)c;
try
{
CarpetExpression ex = new CarpetExpression(module.getCode(), cc.s, cc.origin);
ex.getExpr().asAModule(module);
CarpetExpression ex = new CarpetExpression(module, module.getCode(), cc.s, cc.origin);
ex.getExpr().asATextSource();
ex.scriptRunCommand(this, cc.origin);
}
catch (CarpetExpressionException e) // hopefully that error got reported already
{
throw new InternalExpressionException(e.getMessage());
}
return true;
}
@Override
public void delFunction(String funName)
public void delFunction(Module module, String funName)
{
super.delFunction(funName);
super.delFunction(module, funName);
// mcarpet
if (funName.startsWith("__on_"))
{
@@ -157,7 +146,7 @@ public class CarpetScriptHost extends ScriptHost
{
if (CarpetServer.scriptServer.stopAll)
return "SCARPET PAUSED";
FunctionValue function = globalFunctions.get(call);
FunctionValue function = getFunction(call);
if (function == null)
return "UNDEFINED";
List<LazyValue> argv = new ArrayList<>();
@@ -170,9 +159,10 @@ public class CarpetScriptHost extends ScriptHost
switch (tok.type)
{
case VARIABLE:
if (globalVariables.containsKey(tok.surface.toLowerCase(Locale.ROOT)))
LazyValue var = getGlobalVariable(tok.surface.toLowerCase(Locale.ROOT));
if (var != null)
{
argv.add(globalVariables.get(tok.surface.toLowerCase(Locale.ROOT)));
argv.add(var);
break;
}
case STRINGPARAM:
@@ -238,7 +228,7 @@ public class CarpetScriptHost extends 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(
return function.getExpression().evalValue(
() -> function.lazyEval(context, Context.VOID, function.getExpression(), function.getToken(), argv),
context,
Context.VOID
@@ -262,7 +252,7 @@ public class CarpetScriptHost extends 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(
return fun.getExpression().evalValue(
() -> fun.lazyEval(context, Context.VOID, fun.getExpression(), fun.getToken(), argv),
context,
Context.VOID);
@@ -281,7 +271,7 @@ public class CarpetScriptHost extends ScriptHost
if (this.saveTimeout > 0)
dumpState();
FunctionValue closing = globalFunctions.get("__on_close");
FunctionValue closing = getFunction("__on_close");
if (closing != null)
{
try
@@ -294,7 +284,7 @@ public class CarpetScriptHost extends ScriptHost
}
userHosts.forEach((key, value) ->
{
FunctionValue userClosing = value.globalFunctions.get("__on_close");
FunctionValue userClosing = value.getFunction("__on_close");
if (userClosing != null)
{
ServerPlayerEntity player = CarpetServer.minecraft_server.getPlayerManager().getPlayer(key);
@@ -373,7 +363,7 @@ public class CarpetScriptHost extends ScriptHost
public void setChatErrorSnooper(ServerCommandSource source)
{
errorSnooper = (expr, token, message) ->
errorSnooper = (expr, /*Nullable*/ token, message) ->
{
try
{
@@ -383,18 +373,27 @@ public class CarpetScriptHost extends ScriptHost
{
return null;
}
String[] lines = expr.getCodeString().split("\n");
String shebang = message;
if (expr.module != null)
{
shebang += " in " + expr.module.getName() + "";
}
else
{
shebang += " in system chat";
}
if (token != null)
{
String[] lines = expr.getCodeString().split("\n");
if (lines.length > 1)
{
shebang += " at line " + (token.lineno + 1) + ", pos " + (token.linepos + 1);
}
else {
shebang += " at pos "+(token.pos+1);
}
if (expr.getName() != null)
else
{
shebang += " in "+expr.getName()+"";
shebang += " at pos " + (token.pos + 1);
}
Messenger.m(source, "r " + shebang);
if (lines.length > 1 && token.lineno > 0)
@@ -407,6 +406,11 @@ public class CarpetScriptHost extends ScriptHost
{
Messenger.m(source, "l " + lines[token.lineno + 1]);
}
}
else
{
Messenger.m(source, "r " + shebang);
}
return new ArrayList<>();
};
}
@@ -7,7 +7,7 @@ import carpet.script.value.StringValue;
import carpet.CarpetSettings;
import carpet.CarpetServer;
import carpet.script.bundled.FileModule;
import carpet.script.bundled.ModuleInterface;
import carpet.script.bundled.Module;
import carpet.script.exception.InvalidCallbackException;
import carpet.script.value.Value;
import carpet.utils.Messenger;
@@ -40,7 +40,7 @@ public class CarpetScriptServer
private final Set<String> holyMoly;
public final CarpetEventServer events;
private static final List<ModuleInterface> bundledModuleData = new ArrayList<ModuleInterface>(){{
private static final List<Module> bundledModuleData = new ArrayList<Module>(){{
add(new BundledModule("camera"));
add(new BundledModule("event_test"));
add(new BundledModule("stats_test"));
@@ -69,7 +69,7 @@ public class CarpetScriptServer
}
public ModuleInterface getModule(String name)
public Module getModule(String name)
{
File folder = CarpetServer.minecraft_server.getLevelStorage().resolveFile(
CarpetServer.minecraft_server.getLevelName(), "scripts");
@@ -82,7 +82,7 @@ public class CarpetScriptServer
return new FileModule(script);
}
}
for (ModuleInterface moduleData : bundledModuleData)
for (Module moduleData : bundledModuleData)
{
if (moduleData.getName().equalsIgnoreCase(name))
{
@@ -97,7 +97,7 @@ public class CarpetScriptServer
List<String> moduleNames = new ArrayList<>();
if (includeBuiltIns)
{
for (ModuleInterface mi : bundledModuleData)
for (Module mi : bundledModuleData)
{
moduleNames.add(mi.getName());
}
@@ -129,7 +129,7 @@ public class CarpetScriptServer
{
//TODO add per player modules to support player actions better on a server
name = name.toLowerCase(Locale.ROOT);
ModuleInterface module = getModule(name);
Module module = getModule(name);
if (module == null)
{
Messenger.m(source, "r Failed to add "+name+" app");
@@ -170,13 +170,13 @@ public class CarpetScriptServer
private boolean addConfig(ServerCommandSource source, String hostName)
{
CarpetScriptHost host = modules.get(hostName);
if (host == null || !host.globalFunctions.containsKey("__config"))
if (host == null || host.getFunction("__config") == null)
{
return false;
}
try
{
Value ret = host.callUDF(BlockPos.ORIGIN, source, host.globalFunctions.get("__config"), Collections.emptyList());
Value ret = host.callUDF(BlockPos.ORIGIN, source, host.getFunction("__config"), Collections.emptyList());
if (!(ret instanceof MapValue)) return false;
Map<Value, Value> config = ((MapValue) ret).getMap();
host.setPerPlayer(config.getOrDefault(new StringValue("scope"), new StringValue("player")).getString().equalsIgnoreCase("player"));
@@ -195,7 +195,7 @@ public class CarpetScriptServer
{
return;
}
if (!host.globalFunctions.containsKey("__command"))
if (host.getFunction("__command") == null)
{
Messenger.m(source, "gi "+hostName+" app loaded.");
return;
@@ -217,11 +217,11 @@ public class CarpetScriptServer
return 1;
});
for (String function : host.getPublicFunctions())
for (String function : host.globaFunctionNames(host.myCode, s -> !s.startsWith("_")).sorted().collect(Collectors.toList()))
{
command = command.
then(literal(function).
requires((player) -> modules.containsKey(hostName) && modules.get(hostName).getPublicFunctions().contains(function)).
requires((player) -> modules.containsKey(hostName) && modules.get(hostName).getFunction(function) != null).
executes( (c) -> {
String response = modules.get(hostName).retrieveForExecution(c.getSource()).
call(c.getSource(), function,null,"");
+22 -17
View File
@@ -1,5 +1,7 @@
package carpet.script;
import carpet.script.value.Value;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
@@ -26,38 +28,26 @@ public class Context
this.host = host;
}
LazyValue getVariable(String name)
{
if (variables.containsKey(name))
{
return variables.get(name);
}
return host.globalVariables.get(name);
}
public void setVariable(String name, LazyValue lv)
{
if (name.startsWith("global_"))
{
host.globalVariables.put(name, lv);
return;
}
variables.put(name, lv);
}
boolean isAVariable(String name)
{
return variables.containsKey(name) || host.globalVariables.containsKey(name);
}
void delVariable(String variable)
{
variables.remove(variable);
}
public void removeVariablesMatching(String varname)
{
variables.entrySet().removeIf(e -> e.getKey().startsWith(varname));
}
public Context with(String variable, LazyValue lv)
{
variables.put(variable, lv);
@@ -70,6 +60,21 @@ public class Context
}
public Context recreate()
{
Context ctx = duplicate();
ctx.initialize();
return ctx;
}
protected void initialize()
{
//special variables for second order functions so we don't need to check them all the time
variables.put("_", (c, t) -> Value.ZERO);
variables.put("_i", (c, t) -> Value.ZERO);
variables.put("_a", (c, t) -> Value.ZERO);
}
public Context duplicate()
{
return new Context(this.host);
}
+81 -96
View File
@@ -11,12 +11,13 @@ import carpet.script.Fluff.QuadFunction;
import carpet.script.Fluff.QuinnFunction;
import carpet.script.Fluff.SexFunction;
import carpet.script.Fluff.TriFunction;
import carpet.script.bundled.ModuleInterface;
import carpet.script.bundled.Module;
import carpet.script.exception.BreakStatement;
import carpet.script.exception.ContinueStatement;
import carpet.script.exception.ExitStatement;
import carpet.script.exception.ExpressionException;
import carpet.script.exception.InternalExpressionException;
import carpet.script.exception.ResolvedException;
import carpet.script.exception.ReturnStatement;
import carpet.script.exception.ThrowStatement;
import carpet.script.value.AbstractListValue;
@@ -332,7 +333,7 @@ import static java.lang.Math.min;
* </p>
*/
public class Expression implements Cloneable
public class Expression
{
private static final Map<String, Integer> precedence = new HashMap<String,Integer>() {{
put("attribute~:", 80);
@@ -366,21 +367,18 @@ public class Expression implements Cloneable
private boolean allowNewlineSubstitutions = true;
private boolean allowComments = false;
public ModuleInterface module = null;
public Module module = null;
void asAModule(ModuleInterface mi)
void asATextSource()
{
allowNewlineSubstitutions = false;
allowComments = true;
module = mi;
}
private String name;
String getName() {return name;}
Expression withName(String alias)
void asAModule(Module mi)
{
name = alias;
return this;
module = mi;
}
/** Cached AST (Abstract Syntax Tree) (root) of the expression */
@@ -393,18 +391,6 @@ public class Expression implements Cloneable
private final Map<String, ILazyFunction> functions = new Object2ObjectOpenHashMap<>();
Set<String> getFunctionNames() {return functions.keySet();}
@Override
protected Expression clone() throws CloneNotSupportedException
{
// very very shallow copy for global functions to grab the context for error msgs
Expression copy = (Expression) super.clone();
copy.expression = this.expression;
copy.name = this.name;
copy.module = this.module;
return copy;
}
static List<String> getExpressionSnippet(Tokenizer.Token token, Expression expr)
{
String code = expr.getCodeString();
@@ -561,7 +547,7 @@ public class Expression implements Cloneable
return new ExpressionException(c, e, token, exc.getMessage(), ((InternalExpressionException) exc).stack);
if (exc instanceof ArithmeticException)
return new ExpressionException(c, e, token, "Your math is wrong, "+exc.getMessage());
if (exc instanceof ExpressionException)
if (exc instanceof ResolvedException)
return exc;
// unexpected really - should be caught earlier and converted to InternalExpressionException
exc.printStackTrace();
@@ -669,29 +655,29 @@ public class Expression implements Cloneable
}
});
}
private FunctionValue 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> outers, LazyValue code)
{
name = name.toLowerCase(Locale.ROOT);
if (functions.containsKey(name))
throw new ExpressionException(context, expr, token, "Function "+name+" would mask a built-in function");
Map<String, LazyValue> contextValues = new HashMap<>();
for (String global : globals)
for (String outer : outers)
{
LazyValue lv = context.getVariable(global);
LazyValue lv = context.getVariable(outer);
if (lv == null)
{
throw new InternalExpressionException("Variable "+global+" needs to be defined in outer scope to be used as outer parameter");
throw new InternalExpressionException("Variable "+outer+" needs to be defined in outer scope to be used as outer parameter, and cannot be global");
}
else
{
contextValues.put(global, lv);
contextValues.put(outer, lv);
}
}
if (contextValues.isEmpty()) contextValues = null;
FunctionValue result = new FunctionValue(expr, token, name, code, arguments, contextValues);
// do not store lambda definitions
if (!name.equals("_")) context.host.addUserDefinedFunction(name, result);
if (!name.equals("_")) context.host.addUserDefinedFunction(module, name, result);
return result;
}
@@ -869,11 +855,13 @@ public class Expression implements Cloneable
public void UserDefinedFunctionsAndControlFlow() // public just to get the javadoc right
{
// artificial construct to handle user defined functions and function definitions
addLazyFunction("import", 1, (c, t, lv) ->
addLazyFunction("import", -1, (c, t, lv) ->
{
boolean success = c.host.importModule(c, lv.get(0).evalValue(c).getString());
Value ret = new NumericValue(success);
return (cc, tt) -> ret;
if (lv.size() < 2) throw new InternalExpressionException("'import' needs at least a module name to import, and list of values to import");
String moduleName = lv.get(0).evalValue(c).getString();
c.host.importModule(c, moduleName);
c.host.importNames(c, module, moduleName, lv.subList(1, lv.size()).stream().map((l) -> l.evalValue(c).getString()).collect(Collectors.toList()));
return (cc, tt) -> Value.NULL;
});
addLazyFunctionWithDelegation("call",-1, (c, t, expr, tok, lv) -> { // adjust based on c
@@ -886,9 +874,7 @@ public class Expression implements Cloneable
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 = c.host.getAssertFunction(module, name);
}
List<LazyValue> lvargs = new ArrayList<>(lv.size()-1);
for (int i=1; i< lv.size(); i++)
@@ -1255,7 +1241,7 @@ public class Expression implements Cloneable
{
String lname = li.next().getVariable();
Value vval = ri.next().reboundedTo(lname);
c.setVariable(lname, (cc, tt) -> vval);
setAnyVariable(c, lname, (cc, tt) -> vval);
}
return (cc, tt) -> Value.TRUE;
}
@@ -1272,7 +1258,7 @@ public class Expression implements Cloneable
String varname = v1.getVariable();
Value copy = v2.reboundedTo(varname);
LazyValue boundedLHS = (cc, tt) -> copy;
c.setVariable(varname, boundedLHS);
setAnyVariable(c, varname, boundedLHS);
return boundedLHS;
});
@@ -1294,7 +1280,7 @@ public class Expression implements Cloneable
Value lval = li.next();
String lname = lval.getVariable();
Value result = lval.add(ri.next()).bindTo(lname);
c.setVariable(lname, (cc, tt) -> result);
setAnyVariable(c, lname, (cc, tt) -> result);
}
return (cc, tt) -> Value.TRUE;
}
@@ -1323,7 +1309,7 @@ public class Expression implements Cloneable
Value result = v1.add(v2).bindTo(varname);
boundedLHS = (cc, tt) -> result;
}
c.setVariable(varname, boundedLHS);
setAnyVariable(c, varname, boundedLHS);
return boundedLHS;
});
@@ -1349,8 +1335,8 @@ public class Expression implements Cloneable
String rname = rval.getVariable();
lval.reboundedTo(rname);
rval.reboundedTo(lname);
c.setVariable(lname, (cc, tt) -> rval);
c.setVariable(rname, (cc, tt) -> lval);
setAnyVariable(c, lname, (cc, tt) -> rval);
setAnyVariable(c, rname, (cc, tt) -> lval);
}
return (cc, tt) -> Value.TRUE;
}
@@ -1360,8 +1346,8 @@ public class Expression implements Cloneable
String rvalvar = v2.getVariable();
Value lval = v2.reboundedTo(lvalvar);
Value rval = v1.reboundedTo(rvalvar);
c.setVariable(lvalvar, (cc, tt) -> lval);
c.setVariable(rvalvar, (cc, tt) -> rval);
setAnyVariable(c, lvalvar, (cc, tt) -> lval);
setAnyVariable(c, rvalvar, (cc, tt) -> rval);
return (cc, tt) -> lval;
});
@@ -2991,9 +2977,7 @@ public class Expression implements Cloneable
addLazyFunction("var", 1, (c, t, lv) -> {
String varname = lv.get(0).evalValue(c).getString();
if (!c.isAVariable(varname))
c.setVariable(varname, (_c, _t ) -> Value.ZERO.reboundedTo(varname));
return c.getVariable(varname);
return getOrSetAnyVariable(c, varname);
});
addLazyFunction("undef", 1, (c, t, lv) ->
@@ -3001,7 +2985,7 @@ public class Expression implements Cloneable
Value remove = lv.get(0).evalValue(c);
if (remove instanceof FunctionValue)
{
c.host.delFunction(remove.getString());
c.host.delFunction(module, remove.getString());
return (cc, tt) -> Value.NULL;
}
String varname = remove.getString();
@@ -3010,33 +2994,24 @@ public class Expression implements Cloneable
varname = varname.replaceAll("\\*+$", "");
if (isPrefix)
{
for (String key: c.host.globalFunctions.keySet())
{
if (key.startsWith(varname)) c.host.delFunction(key);
}
c.host.delFunctionWithPrefix(module, varname);
if (varname.startsWith("global_"))
{
for (String key : c.host.globalVariables.keySet())
{
if (key.startsWith(varname)) c.host.delGlobalVariable(key);
c.host.delGlobalVariableWithPrefix(module, varname);
}
}
if (!varname.startsWith("_"))
else if (!varname.startsWith("_"))
{
for (String key : c.variables.keySet())
{
if (key.startsWith(varname)) c.delVariable(key);
}
c.removeVariablesMatching(varname);
}
}
else
{
c.host.delFunction(varname);
c.host.delFunction(module, varname);
if (varname.startsWith("global_"))
{
c.host.delGlobalVariable(varname);
c.host.delGlobalVariable(module, varname);
}
if (!varname.startsWith("_"))
else if (!varname.startsWith("_"))
{
c.delVariable(varname);
}
@@ -3044,25 +3019,17 @@ public class Expression implements Cloneable
return (cc, tt) -> Value.NULL;
});
//deprecate
addLazyFunction("vars", 1, (c, t, lv) -> {
String prefix = lv.get(0).evalValue(c).getString();
List<Value> values = new ArrayList<>();
if (prefix.startsWith("global"))
{
for (String k: c.host.globalVariables.keySet())
{
if (k.startsWith(prefix))
values.add(new StringValue(k));
}
c.host.globaVariableNames(module, (s) -> s.startsWith(prefix)).forEach(s -> values.add(new StringValue(s)));
}
else
{
for (String k: c.getAllVariableNames())
{
if (k.startsWith(prefix))
values.add(new StringValue(k));
}
c.getAllVariableNames().stream().filter(s -> s.startsWith(prefix)).forEach(s -> values.add(new StringValue(s)));
}
Value retval = ListValue.wrap(values);
return (cc, tt) -> retval;
@@ -3075,9 +3042,7 @@ public class Expression implements Cloneable
if (!(funcDesc instanceof FunctionValue))
{
String name = funcDesc.getString();
funcDesc = c.host.globalFunctions.get(name);
if (funcDesc == null)
throw new InternalExpressionException("Function "+name+" is not defined yet");
funcDesc = c.host.getAssertFunction(module, name);
}
FunctionValue fun = (FunctionValue)funcDesc;
int extraargs = lv.size() - fun.getArguments().size();
@@ -3127,6 +3092,33 @@ public class Expression implements Cloneable
}
private void setAnyVariable(Context c, String name, LazyValue lv)
{
if (name.startsWith("global_"))
{
c.host.setGlobalVariable(module, name, lv);
}
else
{
c.setVariable(name, lv);
}
}
private LazyValue getOrSetAnyVariable(Context c, String name)
{
LazyValue var = null;
if (!name.startsWith("global_"))
{
var = c.getVariable(name);
if (var != null) return var;
}
var = c.host.getGlobalVariable(module, name);
if (var != null) return var;
var = (_c, _t ) -> Value.ZERO.reboundedTo(name);
setAnyVariable(c, name, var);
return var;
}
static final Expression none = new Expression("null");
/**
* @param expression .
@@ -3143,6 +3135,7 @@ public class Expression implements Cloneable
BasicDataStructures();
}
private List<Tokenizer.Token> shuntingYard(Context c)
{
List<Tokenizer.Token> outputQueue = new ArrayList<>();
@@ -3267,7 +3260,7 @@ public class Expression implements Cloneable
}
if (stack.isEmpty())
{
throw new ExpressionException(c, "Mismatched parentheses");
throw new ExpressionException(c, this, "Mismatched parentheses");
}
stack.pop();
if (!stack.isEmpty() && stack.peek().type == Tokenizer.Token.TokenType.FUNCTION)
@@ -3325,7 +3318,7 @@ public class Expression implements Cloneable
return evalValue(() -> ast, c, expectedType);
}
static Value evalValue(Supplier<LazyValue> exprProvider, Context c, Integer expectedType)
Value evalValue(Supplier<LazyValue> exprProvider, Context c, Integer expectedType)
{
try
{
@@ -3333,7 +3326,7 @@ public class Expression implements Cloneable
}
catch (ContinueStatement | BreakStatement | ReturnStatement exc)
{
throw new ExpressionException(c, "Control flow functions, like continue, break, or return, should only be used in loops and functions respectively.");
throw new ExpressionException(c, this, "Control flow functions, like continue, break, or return, should only be used in loops and functions respectively.");
}
catch (ExitStatement exit)
{
@@ -3341,15 +3334,15 @@ public class Expression implements Cloneable
}
catch (StackOverflowError ignored)
{
throw new ExpressionException(c, "Your thoughts are too deep");
throw new ExpressionException(c, this, "Your thoughts are too deep");
}
catch (InternalExpressionException exc)
{
throw new ExpressionException(c, "Your expression result is incorrect:"+exc.getMessage());
throw new ExpressionException(c, this, "Your expression result is incorrect:"+exc.getMessage());
}
catch (ArithmeticException exc)
{
throw new ExpressionException(c, "The final result is incorrect, "+exc.getMessage());
throw new ExpressionException(c, this, "The final result is incorrect, "+exc.getMessage());
}
}
@@ -3376,15 +3369,7 @@ public class Expression implements Cloneable
stack.push(result);
break;
case VARIABLE:
stack.push((c, t) ->
{
if (!c.isAVariable(token.surface)) // new variable
{
c.setVariable(token.surface, (cc, tt ) -> Value.ZERO.reboundedTo(token.surface));
}
LazyValue lazyVariable = c.getVariable(token.surface);
return lazyVariable.evalValue(c);
});
stack.push((c, t) -> getOrSetAnyVariable(c, token.surface).evalValue(c));
break;
case FUNCTION:
String name = token.surface.toLowerCase(Locale.ROOT);
@@ -3507,15 +3492,15 @@ public class Expression implements Cloneable
if (stack.size() > 1)
{
throw new ExpressionException(c, "Too many unhandled function parameter lists");
throw new ExpressionException(c, this, "Too many unhandled function parameter lists");
}
else if (stack.peek() > 1)
{
throw new ExpressionException(c, "Too many numbers or variables");
throw new ExpressionException(c, this, "Too many numbers or variables");
}
else if (stack.peek() < 1)
{
throw new ExpressionException(c, "Empty expression");
throw new ExpressionException(c, this, "Empty expression");
}
}
@@ -1,6 +1,5 @@
package carpet.script;
import carpet.script.exception.ExpressionException;
import org.apache.commons.lang3.StringUtils;
import java.util.Collections;
@@ -21,31 +20,17 @@ public class ExpressionInspector
return Expression.getExpressionSnippet(token, expr);
}
public static String Expression_getName(Expression e)
public static String Expression_getModuleName(Expression e)
{
return e.getName();
}
public static Expression Expression_cloneWithName(Expression e, Context c, String name, Tokenizer.Token token)
{
Expression copy;
try
{
copy = e.clone();
}
catch (CloneNotSupportedException ex)
{
throw new ExpressionException(c, e, token, "Problems in allocating global function "+name);
}
return copy.withName(name);
return e.module == null?null:e.module.getName();
}
private static TreeSet<String> scarpetFunctions;
private static TreeSet<String> APIFunctions;
static
{
Set<String> allFunctions = (new CarpetExpression("null", null, null)).getExpr().getFunctionNames();
scarpetFunctions = new TreeSet<>(new Expression("null").getFunctionNames());
Set<String> allFunctions = (new CarpetExpression(null, "null", null, null)).getExpr().getFunctionNames();
scarpetFunctions = new TreeSet<>(Expression.none.getFunctionNames());
APIFunctions = allFunctions.stream().filter(s -> !scarpetFunctions.contains(s)).collect(Collectors.toCollection(TreeSet::new));
}
@@ -63,10 +48,8 @@ public class ExpressionInspector
// not that useful in commandline, more so in external scripts, so skipping here
//scarpetMatches.addAll(CarpetServer.scriptServer.events.eventHandlers.keySet().stream().
// filter(s -> s.startsWith(prefix) && s.length() <= maxLen).map(s -> "__"+s+"(").collect(Collectors.toList()));
scarpetMatches.addAll(host.globalFunctions.keySet().stream().
filter(s -> s.startsWith(prefix)).map(s -> s+"(").collect(Collectors.toList()));
scarpetMatches.addAll(host.globalVariables.keySet().stream().
filter(s -> s.startsWith(prefix)).collect(Collectors.toList()));
scarpetMatches.addAll(host.globaFunctionNames(host.myCode, s -> s.startsWith(prefix)).map(s -> s+"(").collect(Collectors.toList()));
scarpetMatches.addAll(host.globaVariableNames(host.myCode, s -> s.startsWith(prefix)).collect(Collectors.toList()));
return scarpetMatches;
}
}
+237 -56
View File
@@ -1,111 +1,292 @@
package carpet.script;
import carpet.script.bundled.ModuleInterface;
import carpet.script.bundled.Module;
import carpet.script.exception.InternalExpressionException;
import carpet.script.value.FunctionValue;
import carpet.script.value.Value;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import java.util.HashSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.function.Predicate;
import java.util.stream.Stream;
public abstract class ScriptHost
{
protected final Map<String, ScriptHost> userHosts = new Object2ObjectOpenHashMap<>();
public class ModuleData
{
Module parent;
public Map<String, FunctionValue> globalFunctions = new Object2ObjectOpenHashMap<>();
public Map<String, LazyValue> globalVariables = new Object2ObjectOpenHashMap<>();
private Set<String> imports = new HashSet<>();
public Map<String, ModuleData> functionImports = new Object2ObjectOpenHashMap<>(); // imported functions string to module
public Map<String, ModuleData> globalsImports = new Object2ObjectOpenHashMap<>(); // imported global variables string to module
public Map<String, ModuleData> futureImports = new Object2ObjectOpenHashMap<>(); // imports not known before used
public ModuleData(Module parent, ModuleData other)
{
// imports are just pointers, but they still point to the wrong modules (point to the parent)
this.parent = parent;
globalFunctions.putAll(other.globalFunctions);
other.globalVariables.forEach((key, value) ->
{
Value var = value.evalValue(null);
Value copy = var.deepcopy();
copy.boundVariable = var.boundVariable;
globalVariables.put(key, (c, t) -> copy);
});
}
public void setImportsBasedOn(ScriptHost host, ModuleData other)
{
// fixing imports
other.functionImports.forEach((name, targetData) -> {
functionImports.put(name, host.moduleData.get(targetData.parent));
});
other.globalsImports.forEach((name, targetData) -> {
globalsImports.put(name, host.moduleData.get(targetData.parent));
});
other.futureImports.forEach((name, targetData) -> {
futureImports.put(name, host.moduleData.get(targetData.parent));
});
}
public ModuleData(Module parent)
{
this.parent = parent;
}
}
protected final Map<String, ScriptHost> userHosts = new Object2ObjectOpenHashMap<>();
private Map<Module,ModuleData> moduleData = new HashMap<>(); // marking imports
private Map<String,Module> modules = new HashMap<>();
protected ScriptHost parent;
protected boolean perUser;
//private String name;
public String getName() {return myCode==null?null:myCode.getName();}
protected final ModuleInterface myCode;
public final Module myCode;
public Fluff.TriFunction<Expression, Tokenizer.Token, String, List<String>> errorSnooper = null;
ScriptHost(ModuleInterface code, boolean perUser, ScriptHost parent)
protected ScriptHost(Module code, boolean perUser, ScriptHost parent)
{
this.parent = parent;
//this.name = name;
this.myCode = code;
this.perUser = perUser;
if (code != null) imports.add(code.getName());
globalVariables.put("euler", (c, t) -> Expression.euler);
globalVariables.put("pi", (c, t) -> Expression.PI);
globalVariables.put("null", (c, t) -> Value.NULL);
globalVariables.put("true", (c, t) -> Value.TRUE);
globalVariables.put("false", (c, t) -> Value.FALSE);
//special variables for second order functions so we don't need to check them all the time
globalVariables.put("_", (c, t) -> Value.ZERO);
globalVariables.put("_i", (c, t) -> Value.ZERO);
globalVariables.put("_a", (c, t) -> Value.ZERO);
ModuleData moduleData = new ModuleData(code);
initializeModuleGlobals(moduleData);
this.moduleData.put(code, moduleData);
this.modules.put(code==null?null:code.getName(), code);
}
public void addUserDefinedFunction(String funName, FunctionValue function)
void initializeModuleGlobals(ModuleData md)
{
globalFunctions.put(funName, function);
md.globalVariables.put("euler", (c, t) -> Expression.euler);
md.globalVariables.put("pi", (c, t) -> Expression.PI);
md.globalVariables.put("null", (c, t) -> Value.NULL);
md.globalVariables.put("true", (c, t) -> Value.TRUE);
md.globalVariables.put("false", (c, t) -> Value.FALSE);
}
public boolean importModule(Context c, String moduleName)
public void importModule(Context c, String moduleName)
{
if (imports.contains(moduleName)) return false; // aready imported
ModuleInterface module = getModuleByName(moduleName);
if (imports.contains(module.getName())) return false; // aready imported, once again, in case some discrepancies
imports.add(module.getName());
if (runModuleCode(c, module))
if (modules.containsKey(moduleName)) return; // aready imported
Module module = getModuleByName(moduleName);
if (modules.containsKey(module.getName())) return; // aready imported, once again, in case some discrepancies in names?
modules.put(module.getName(), module);
ModuleData data = new ModuleData(module);
initializeModuleGlobals(data);
moduleData.put(module, data);
runModuleCode(c, module);
//moduleData.remove(module); // we are pooped already, but doesn't hurt to clean that up.
//modules.remove(module.getName());
//throw new InternalExpressionException("Failed to import a module "+moduleName);
}
public void importNames(Context c, Module targetModule, String sourceModuleName, List<String> identifiers )
{
return true;
if (!moduleData.containsKey(targetModule))
{
throw new InternalExpressionException("Cannot import to module that doesn't exist");
}
Module source = modules.get(sourceModuleName);
ModuleData sourceData = moduleData.get(source);
ModuleData targetData = moduleData.get(targetModule);
if (sourceData == null || targetData == null)
{
throw new InternalExpressionException("Cannot import from module that is not imported");
}
for (String identifier: identifiers)
{
if (sourceData.globalFunctions.containsKey(identifier))
{
targetData.functionImports.put(identifier, sourceData);
}
else if (sourceData.globalVariables.containsKey(identifier))
{
targetData.globalsImports.put(identifier, sourceData);
}
else
{
targetData.functionImports.put(identifier, sourceData);
}
}
imports.remove(module.getName());
return false;
}
protected abstract ModuleInterface getModuleByName(String name); // this should be shell out in the executuor
protected abstract Module getModuleByName(String name); // this should be shell out in the executor
protected abstract boolean runModuleCode(Context c, ModuleInterface module); // this should be shell out in the executuor
protected abstract void runModuleCode(Context c, Module module); // this should be shell out in the executor
public void delFunction(String funName)
public FunctionValue getFunction(String name) { return getFunction(myCode, name); }
public FunctionValue getAssertFunction(Module module, String name)
{
globalFunctions.remove(funName);
FunctionValue ret = getFunction(module, name);
if (ret == null) throw new InternalExpressionException("Function "+name+" is not defined yet");
return ret;
}
private FunctionValue getFunction(Module module, String name)
{
ModuleData local = moduleData.get(module);
FunctionValue ret = local.globalFunctions.get(name); // most uses would be from local scope anyways
if (ret != null) return ret;
ModuleData target = local.functionImports.get(name);
if (target != null)
{
ret = target.globalFunctions.get(name);
if (ret != null) return ret;
}
// not in local scope - will need to travel over import links
target = local.futureImports.get(name);
if (target == null) return null;
target = findModuleDataFromFunctionImports(name, target, 0);
if (target == null) return null;
local.futureImports.remove(name);
local.functionImports.put(name, target);
return target.globalFunctions.get(name);
}
public void delGlobalVariable(String varName)
private ModuleData findModuleDataFromFunctionImports(String name, ModuleData source, int ttl)
{
globalVariables.remove(varName);
if (ttl > 10) throw new InternalExpressionException("Cannot import "+name+", either your imports are too deep or too loopy");
if (source.globalFunctions.containsKey(name))
return source;
if (source.functionImports.containsKey(name))
return findModuleDataFromFunctionImports(name, source.functionImports.get(name), ttl+1);
if (source.futureImports.containsKey(name))
return findModuleDataFromFunctionImports(name, source.futureImports.get(name), ttl+1);
return null;
}
public LazyValue getGlobalVariable(String name) { return getGlobalVariable(myCode, name); }
public LazyValue getGlobalVariable(Module module, String name)
{
ModuleData local = moduleData.get(module);
LazyValue ret = local.globalVariables.get(name); // most uses would be from local scope anyways
if (ret != null) return ret;
ModuleData target = local.globalsImports.get(name);
if (target != null)
{
ret = target.globalVariables.get(name);
if (ret != null) return ret;
}
// not in local scope - will need to travel over import links
target = local.futureImports.get(name);
if (target == null) return null;
target = findModuleDataFromGlobalImports(name, target, 0);
if (target == null) return null;
local.futureImports.remove(name);
local.globalsImports.put(name, target);
return target.globalVariables.get(name);
}
private ModuleData findModuleDataFromGlobalImports(String name, ModuleData source, int ttl)
{
if (ttl > 10) throw new InternalExpressionException("Cannot import "+name+", either your imports are too deep or too loopy");
if (source.globalVariables.containsKey(name))
return source;
if (source.globalsImports.containsKey(name))
return findModuleDataFromGlobalImports(name, source.globalsImports.get(name), ttl+1);
if (source.futureImports.containsKey(name))
return findModuleDataFromGlobalImports(name, source.futureImports.get(name), ttl+1);
return null;
}
public void delFunctionWithPrefix(Module module, String prefix)
{
ModuleData data = moduleData.get(module);
data.globalFunctions.entrySet().removeIf(e -> e.getKey().startsWith(prefix));
data.functionImports.entrySet().removeIf(e -> e.getKey().startsWith(prefix));
}
public void delFunction(Module module, String funName)
{
ModuleData data = moduleData.get(module);
data.globalFunctions.remove(funName);
data.functionImports.remove(funName);
}
public void delGlobalVariableWithPrefix(Module module, String prefix)
{
ModuleData data = moduleData.get(module);
data.globalVariables.entrySet().removeIf(e -> e.getKey().startsWith(prefix));
data.globalsImports.entrySet().removeIf(e -> e.getKey().startsWith(prefix));
}
public void delGlobalVariable(Module module, String varName)
{
ModuleData data = moduleData.get(module);
data.globalFunctions.remove(varName);
data.functionImports.remove(varName);
}
public void addUserDefinedFunction(Module module, String name, FunctionValue fun)
{
moduleData.get(module).globalFunctions.put(name, fun);
}
public void setGlobalVariable(Module module, String name, LazyValue lv)
{
moduleData.get(module).globalVariables.put(name, lv);
}
public Stream<String> globaVariableNames(Module module, Predicate<String> predicate)
{
return Stream.concat(
moduleData.get(module).globalVariables.keySet().stream(),
moduleData.get(module).globalsImports.keySet().stream()
).filter(predicate);
}
public Stream<String> globaFunctionNames(Module module, Predicate<String> predicate)
{
return Stream.concat(
moduleData.get(module).globalFunctions.keySet().stream(),
moduleData.get(module).functionImports.keySet().stream()
).filter(predicate);
}
public ScriptHost retrieveForExecution(String /*Nullable*/ user)
{
if (!perUser)
return this;
ScriptHost userHost = userHosts.get(user);
if (userHost != null)
return userHost;
userHost = this.duplicate();
userHost.globalVariables.putAll(this.globalVariables);
userHost.globalFunctions.putAll(this.globalFunctions);
userHost.imports.addAll(this.imports);
if (!perUser) return this;
ScriptHost oldUserHost = userHosts.get(user);
if (oldUserHost != null) return oldUserHost;
ScriptHost userHost = this.duplicate();
userHost.modules.putAll(this.modules);
for (Map.Entry<Module, ScriptHost.ModuleData> e : this.moduleData.entrySet())
{
userHost.moduleData.put(e.getKey(), new ModuleData(e.getKey(), e.getValue()));
}
// fixing imports
userHost.moduleData.forEach((module, data) ->
{
data.setImportsBasedOn(this, this.moduleData.get(data.parent));
});
userHosts.put(user, userHost);
return userHost;
}
protected abstract ScriptHost duplicate();
public List<String> getPublicFunctions()
{
return globalFunctions.keySet().stream().filter((str) -> !str.startsWith("_")).sorted().collect(Collectors.toList());
}
public List<String> getAvailableFunctions(boolean all)
{
return globalFunctions.keySet().stream().filter((str) -> all || !str.startsWith("__")).sorted().collect(Collectors.toList());
}
public void onClose() { }
public void setPerPlayer(boolean isPerUser)
@@ -6,7 +6,7 @@ import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
public class BundledModule implements ModuleInterface
public class BundledModule extends Module
{
private String name;
private String code;
@@ -14,7 +14,7 @@ import java.io.IOException;
import java.nio.file.Files;
import java.util.Locale;
public class FileModule implements ModuleInterface
public class FileModule extends Module
{
private String name;
private String code;
@@ -10,13 +10,13 @@ import java.nio.file.Files;
import static carpet.script.bundled.FileModule.read;
import static carpet.script.bundled.FileModule.write;
public interface ModuleInterface
public abstract class Module
{
String getName();
String getCode();
default boolean isInternal() {return true; }
public abstract String getName();
public abstract String getCode();
public boolean isInternal() {return true; }
default Tag getData(String file)
public Tag getData(String file)
{
File dataFile = CarpetServer.minecraft_server.getLevelStorage().resolveFile(
CarpetServer.minecraft_server.getLevelName(), "scripts/"+getName()+".data"+(file==null?"":"."+file)+".nbt");
@@ -24,7 +24,7 @@ public interface ModuleInterface
return read(dataFile);
}
default void saveData(String file, Tag globalState)
public void saveData(String file, Tag globalState)
{
File dataFile =CarpetServer.minecraft_server.getLevelStorage().resolveFile(
CarpetServer.minecraft_server.getLevelName(), "scripts/"+getName()+".data"+(file==null?"":"."+file)+".nbt");
@@ -41,4 +41,10 @@ public interface ModuleInterface
write(globalState, dataFile);
}
@Override
public int hashCode()
{
return getName().hashCode();
}
}
@@ -6,7 +6,7 @@ import net.minecraft.server.command.ServerCommandSource;
import java.util.List;
public class CarpetExpressionException extends RuntimeException
public class CarpetExpressionException extends RuntimeException implements ResolvedException
{
public final List<FunctionValue> stack;
@@ -10,16 +10,17 @@ import java.util.ArrayList;
import java.util.List;
import static carpet.script.ExpressionInspector.Expression_getExpressionSnippet;
import static carpet.script.ExpressionInspector.Expression_getName;
import static carpet.script.ExpressionInspector.Expression_getModuleName;
/* The expression evaluators exception class. */
public class ExpressionException extends RuntimeException
public class ExpressionException extends RuntimeException implements ResolvedException
{
public final Context context;
public final List<FunctionValue> stack = new ArrayList<>();
public ExpressionException(Context c, String message)
public ExpressionException(Context c, Expression e, String message)
{
super(makeMessage(c, null, null, message));
super(makeMessage(c, e, null, message));
context = c;
}
@@ -35,11 +36,12 @@ public class ExpressionException extends RuntimeException
context = c;
}
private static final Fluff.TriFunction<Expression, Tokenizer.Token, String, List<String>> errorMaker = (expr, token, errmessage) ->
private static final Fluff.TriFunction<Expression, Tokenizer.Token, String, List<String>> errorMaker = (expr, /*Nullable*/ token, errmessage) ->
{
List<String> errMsg = new ArrayList<>();
if (expr != null && token != null)
errmessage += Expression_getModuleName(expr) == null?"":(" in "+Expression_getModuleName(expr));
if (token != null)
{
List<String> snippet = Expression_getExpressionSnippet(token, expr);
errMsg.addAll(snippet);
@@ -52,11 +54,6 @@ public class ExpressionException extends RuntimeException
{
errmessage += " at pos " + (token.pos + 1);
}
if (Expression_getName(expr) != null)
{
errmessage += " (" + Expression_getName(expr) + ")";
}
}
errMsg.add(errmessage);
return errMsg;
@@ -0,0 +1,5 @@
package carpet.script.exception;
public interface ResolvedException
{
}
@@ -6,7 +6,6 @@ import carpet.script.ExpressionInspector;
import carpet.script.Fluff;
import carpet.script.LazyValue;
import carpet.script.Tokenizer;
import carpet.script.bundled.ModuleInterface;
import carpet.script.exception.BreakStatement;
import carpet.script.exception.ContinueStatement;
import carpet.script.exception.ExitStatement;
@@ -128,11 +127,9 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
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 (errata: needed to know the package to report with exceptions
Expression callContext = ExpressionInspector.Expression_cloneWithName(e, c, fullName(), t);
try
{
return lazyEval(c, type, callContext, t, lazyParams);
return lazyEval(c, type, e, t, lazyParams);
}
catch (ExpressionException exc)
{
@@ -142,12 +139,12 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
catch (InternalExpressionException exc)
{
exc.stack.add(this);
throw new ExpressionException(c, callContext, t, exc.getMessage(), exc.stack);
throw new ExpressionException(c, e, t, exc.getMessage(), exc.stack);
}
catch (ArithmeticException exc)
{
throw new ExpressionException(c, callContext, t, "Your math is wrong, "+exc.getMessage(), Collections.singletonList(this));
throw new ExpressionException(c, e, t, "Your math is wrong, "+exc.getMessage(), Collections.singletonList(this));
}
}
@@ -190,14 +187,10 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
retVal = throwStatement.retval;
rethrow = true;
}
catch (ArithmeticException | ExitStatement | ExpressionException | InternalExpressionException exc )
{
throw exc; // rethrow so could be contextualized if needed
}
catch (Exception exc)
{
throw new ExpressionException(c, e, t, "Error while evaluating expression: "+exc.getMessage());
}
//catch (ArithmeticException | ExitStatement | ExpressionException | InternalExpressionException exc )
//{
// throw exc; // rethrow so could be contextualized if needed
//}
if (rethrow)
{
throw new ThrowStatement(retVal);