imports and better error reporting and stacktraces
This commit is contained in:
1 parent
15fe9c5ad9
commit
1650f3233b
15 files changed
+351
-245
No files matched your search
@@ -7,9 +7,9 @@ import carpet.script.CarpetEventServer;
|
|||||||
import carpet.script.CarpetExpression;
|
import carpet.script.CarpetExpression;
|
||||||
import carpet.script.Expression;
|
import carpet.script.Expression;
|
||||||
import carpet.script.ExpressionInspector;
|
import carpet.script.ExpressionInspector;
|
||||||
import carpet.script.ScriptHost;
|
|
||||||
import carpet.script.Tokenizer;
|
import carpet.script.Tokenizer;
|
||||||
import carpet.script.exception.CarpetExpressionException;
|
import carpet.script.exception.CarpetExpressionException;
|
||||||
|
import carpet.script.value.FunctionValue;
|
||||||
import carpet.utils.Messenger;
|
import carpet.utils.Messenger;
|
||||||
import com.mojang.brigadier.CommandDispatcher;
|
import com.mojang.brigadier.CommandDispatcher;
|
||||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||||
@@ -50,7 +50,7 @@ public class ScriptCommand
|
|||||||
SuggestionsBuilder suggestionsBuilder
|
SuggestionsBuilder suggestionsBuilder
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
ScriptHost currentHost = getHost(context);
|
CarpetScriptHost currentHost = getHost(context);
|
||||||
String previous = suggestionsBuilder.getRemaining().toLowerCase(Locale.ROOT);
|
String previous = suggestionsBuilder.getRemaining().toLowerCase(Locale.ROOT);
|
||||||
int strlen = previous.length();
|
int strlen = previous.length();
|
||||||
StringBuilder lastToken = new StringBuilder();
|
StringBuilder lastToken = new StringBuilder();
|
||||||
@@ -287,7 +287,7 @@ public class ScriptCommand
|
|||||||
}
|
}
|
||||||
private static Collection<String> suggestFunctionCalls(CommandContext<ServerCommandSource> c)
|
private static Collection<String> suggestFunctionCalls(CommandContext<ServerCommandSource> c)
|
||||||
{
|
{
|
||||||
ScriptHost host = getHost(c);
|
CarpetScriptHost host = getHost(c);
|
||||||
return host.getPublicFunctions();
|
return host.getPublicFunctions();
|
||||||
}
|
}
|
||||||
private static int listEvents(ServerCommandSource source)
|
private static int listEvents(ServerCommandSource source)
|
||||||
@@ -310,16 +310,17 @@ public class ScriptCommand
|
|||||||
}
|
}
|
||||||
private static int listGlobals(CommandContext<ServerCommandSource> context, boolean all)
|
private static int listGlobals(CommandContext<ServerCommandSource> context, boolean all)
|
||||||
{
|
{
|
||||||
ScriptHost host = getHost(context);
|
CarpetScriptHost host = getHost(context);
|
||||||
ServerCommandSource source = context.getSource();
|
ServerCommandSource source = context.getSource();
|
||||||
|
|
||||||
Messenger.m(source, "lb Stored functions"+((host == CarpetServer.scriptServer.globalHost)?":":" in "+host.getName()+":"));
|
Messenger.m(source, "lb Stored functions"+((host == CarpetServer.scriptServer.globalHost)?":":" in "+host.getName()+":"));
|
||||||
for (String fname : host.getAvailableFunctions(all))
|
for (String fname : host.getAvailableFunctions(all))
|
||||||
{
|
{
|
||||||
Expression expr = host.getExpressionForFunction(fname);
|
FunctionValue fun = host.globalFunctions.get(fname);
|
||||||
Tokenizer.Token tok = host.getTokenForFunction(fname);
|
Expression expr = fun.getExpression();
|
||||||
|
Tokenizer.Token tok = fun.getToken();
|
||||||
List<String> snippet = ExpressionInspector.Expression_getExpressionSnippet(tok, expr);
|
List<String> snippet = ExpressionInspector.Expression_getExpressionSnippet(tok, expr);
|
||||||
Messenger.m(source, "wb "+fname,"t defined at: line "+(tok.lineno+1)+" pos "+(tok.linepos+1));
|
Messenger.m(source, "wb "+fun.fullName(),"t defined at: line "+(tok.lineno+1)+" pos "+(tok.linepos+1));
|
||||||
for (String snippetLine: snippet)
|
for (String snippetLine: snippet)
|
||||||
{
|
{
|
||||||
Messenger.m(source, "w "+snippetLine);
|
Messenger.m(source, "w "+snippetLine);
|
||||||
@@ -338,11 +339,11 @@ public class ScriptCommand
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void handleCall(ServerCommandSource source, Supplier<String> call)
|
public static void handleCall(ServerCommandSource source, CarpetScriptHost host, Supplier<String> call)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
CarpetServer.scriptServer.setChatErrorSnooper(source);
|
host.setChatErrorSnooper(source);
|
||||||
long start = System.nanoTime();
|
long start = System.nanoTime();
|
||||||
String result = call.get();
|
String result = call.get();
|
||||||
long time = ((System.nanoTime()-start)/1000);
|
long time = ((System.nanoTime()-start)/1000);
|
||||||
@@ -361,9 +362,10 @@ public class ScriptCommand
|
|||||||
}
|
}
|
||||||
catch (CarpetExpressionException e)
|
catch (CarpetExpressionException e)
|
||||||
{
|
{
|
||||||
Messenger.m(source, "r Exception white evaluating expression at "+new BlockPos(source.getPosition())+": "+e.getMessage());
|
e.printStack(source);
|
||||||
|
Messenger.m(source, "r Exception while evaluating expression at "+new BlockPos(source.getPosition())+": "+e.getMessage());
|
||||||
}
|
}
|
||||||
CarpetServer.scriptServer.resetErrorSnooper();
|
host.resetErrorSnooper();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int invoke(CommandContext<ServerCommandSource> context, String call, BlockPos pos1, BlockPos pos2, String args)
|
private static int invoke(CommandContext<ServerCommandSource> context, String call, BlockPos pos1, BlockPos pos2, String args)
|
||||||
@@ -390,7 +392,7 @@ public class ScriptCommand
|
|||||||
}
|
}
|
||||||
//if (!(args.trim().isEmpty()))
|
//if (!(args.trim().isEmpty()))
|
||||||
// arguments.addAll(Arrays.asList(args.trim().split("\\s+")));
|
// arguments.addAll(Arrays.asList(args.trim().split("\\s+")));
|
||||||
handleCall(source, () -> host.call(source, call, positions, args));
|
handleCall(source, host, () -> host.call(source, call, positions, args));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -398,8 +400,8 @@ public class ScriptCommand
|
|||||||
private static int compute(CommandContext<ServerCommandSource> context, String expr)
|
private static int compute(CommandContext<ServerCommandSource> context, String expr)
|
||||||
{
|
{
|
||||||
ServerCommandSource source = context.getSource();
|
ServerCommandSource source = context.getSource();
|
||||||
ScriptHost host = getHost(context);
|
CarpetScriptHost host = getHost(context);
|
||||||
handleCall(source, () -> {
|
handleCall(source, host, () -> {
|
||||||
CarpetExpression ex = new CarpetExpression(expr, source, new BlockPos(0, 0, 0));
|
CarpetExpression ex = new CarpetExpression(expr, source, new BlockPos(0, 0, 0));
|
||||||
return ex.scriptRunCommand(host, new BlockPos(source.getPosition()));
|
return ex.scriptRunCommand(host, new BlockPos(source.getPosition()));
|
||||||
});
|
});
|
||||||
@@ -409,7 +411,7 @@ public class ScriptCommand
|
|||||||
private static int scriptScan(CommandContext<ServerCommandSource> context, BlockPos origin, BlockPos a, BlockPos b, String expr)
|
private static int scriptScan(CommandContext<ServerCommandSource> context, BlockPos origin, BlockPos a, BlockPos b, String expr)
|
||||||
{
|
{
|
||||||
ServerCommandSource source = context.getSource();
|
ServerCommandSource source = context.getSource();
|
||||||
ScriptHost host = getHost(context);
|
CarpetScriptHost host = getHost(context);
|
||||||
MutableIntBoundingBox area = new MutableIntBoundingBox(a, b);
|
MutableIntBoundingBox area = new MutableIntBoundingBox(a, b);
|
||||||
CarpetExpression cexpr = new CarpetExpression(expr, source, origin);
|
CarpetExpression cexpr = new CarpetExpression(expr, source, origin);
|
||||||
int int_1 = area.getBlockCountX() * area.getBlockCountY() * area.getBlockCountZ();
|
int int_1 = area.getBlockCountX() * area.getBlockCountY() * area.getBlockCountZ();
|
||||||
@@ -441,6 +443,7 @@ public class ScriptCommand
|
|||||||
}
|
}
|
||||||
catch (CarpetExpressionException exc)
|
catch (CarpetExpressionException exc)
|
||||||
{
|
{
|
||||||
|
exc.printStack(source);
|
||||||
Messenger.m(source, "r Error while processing command: "+exc);
|
Messenger.m(source, "r Error while processing command: "+exc);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -458,7 +461,7 @@ public class ScriptCommand
|
|||||||
BlockStateArgument block, Predicate<CachedBlockPosition> replacement, String mode)
|
BlockStateArgument block, Predicate<CachedBlockPosition> replacement, String mode)
|
||||||
{
|
{
|
||||||
ServerCommandSource source = context.getSource();
|
ServerCommandSource source = context.getSource();
|
||||||
ScriptHost host = getHost(context);
|
CarpetScriptHost host = getHost(context);
|
||||||
MutableIntBoundingBox area = new MutableIntBoundingBox(a, b);
|
MutableIntBoundingBox area = new MutableIntBoundingBox(a, b);
|
||||||
CarpetExpression cexpr = new CarpetExpression(expr, source, origin);
|
CarpetExpression cexpr = new CarpetExpression(expr, source, origin);
|
||||||
int int_1 = area.getBlockCountX() * area.getBlockCountY() * area.getBlockCountZ();
|
int int_1 = area.getBlockCountX() * area.getBlockCountY() * area.getBlockCountZ();
|
||||||
@@ -488,6 +491,7 @@ public class ScriptCommand
|
|||||||
}
|
}
|
||||||
catch (CarpetExpressionException e)
|
catch (CarpetExpressionException e)
|
||||||
{
|
{
|
||||||
|
e.printStack(source);
|
||||||
Messenger.m(source, "r Exception while filling the area:\n","l "+e.getMessage());
|
Messenger.m(source, "r Exception while filling the area:\n","l "+e.getMessage());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3376,11 +3376,11 @@ public class CarpetExpression
|
|||||||
}
|
}
|
||||||
catch (ExpressionException e)
|
catch (ExpressionException e)
|
||||||
{
|
{
|
||||||
throw new CarpetExpressionException(e.getMessage());
|
throw new CarpetExpressionException(e.getMessage(), e.stack);
|
||||||
}
|
}
|
||||||
catch (ArithmeticException ae)
|
catch (ArithmeticException ae)
|
||||||
{
|
{
|
||||||
throw new CarpetExpressionException("Math doesn't compute... "+ae.getMessage());
|
throw new CarpetExpressionException("Math doesn't compute... "+ae.getMessage(), null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3423,11 +3423,11 @@ public class CarpetExpression
|
|||||||
}
|
}
|
||||||
catch (ExpressionException e)
|
catch (ExpressionException e)
|
||||||
{
|
{
|
||||||
throw new CarpetExpressionException(e.getMessage());
|
throw new CarpetExpressionException(e.getMessage(), e.stack);
|
||||||
}
|
}
|
||||||
catch (ArithmeticException ae)
|
catch (ArithmeticException ae)
|
||||||
{
|
{
|
||||||
throw new CarpetExpressionException("Math doesn't compute... "+ae.getMessage());
|
throw new CarpetExpressionException("Math doesn't compute... "+ae.getMessage(), null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,13 +2,16 @@ package carpet.script;
|
|||||||
|
|
||||||
import carpet.CarpetServer;
|
import carpet.CarpetServer;
|
||||||
import carpet.script.bundled.ModuleInterface;
|
import carpet.script.bundled.ModuleInterface;
|
||||||
|
import carpet.script.exception.CarpetExpressionException;
|
||||||
import carpet.script.exception.ExpressionException;
|
import carpet.script.exception.ExpressionException;
|
||||||
|
import carpet.script.exception.InternalExpressionException;
|
||||||
import carpet.script.exception.InvalidCallbackException;
|
import carpet.script.exception.InvalidCallbackException;
|
||||||
import carpet.script.value.FunctionValue;
|
import carpet.script.value.FunctionValue;
|
||||||
import carpet.script.value.NumericValue;
|
import carpet.script.value.NumericValue;
|
||||||
import carpet.script.value.StringValue;
|
import carpet.script.value.StringValue;
|
||||||
import carpet.script.value.Value;
|
import carpet.script.value.Value;
|
||||||
import carpet.CarpetSettings;
|
import carpet.CarpetSettings;
|
||||||
|
import carpet.utils.Messenger;
|
||||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.entity.EntityType;
|
import net.minecraft.entity.EntityType;
|
||||||
@@ -33,19 +36,52 @@ public class CarpetScriptHost extends ScriptHost
|
|||||||
private Tag globalState;
|
private Tag globalState;
|
||||||
private int saveTimeout;
|
private int saveTimeout;
|
||||||
|
|
||||||
CarpetScriptHost(CarpetScriptServer server, String name, ModuleInterface code, boolean perUser, ScriptHost parent)
|
private CarpetScriptHost(CarpetScriptServer server, ModuleInterface code, boolean perUser, ScriptHost parent)
|
||||||
{
|
{
|
||||||
super(name, code, perUser, parent);
|
super(code, perUser, parent);
|
||||||
this.saveTimeout = 0;
|
this.saveTimeout = 0;
|
||||||
this.scriptServer = server;
|
this.scriptServer = server;
|
||||||
if (parent == null && name != null)
|
if (parent == null && code != null)
|
||||||
globalState = loadState();
|
globalState = loadState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static CarpetScriptHost create(CarpetScriptServer scriptServer, ModuleInterface 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)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String code = module.getCode();
|
||||||
|
if (code == null)
|
||||||
|
{
|
||||||
|
Messenger.m(source, "r Unable to load "+module.getName()+" app - code not found");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
host.setChatErrorSnooper(source);
|
||||||
|
CarpetExpression ex = new CarpetExpression(code, source, new BlockPos(0, 0, 0));
|
||||||
|
ex.getExpr().asAModule(module);
|
||||||
|
ex.scriptRunCommand(host, new BlockPos(source.getPosition()));
|
||||||
|
}
|
||||||
|
catch (CarpetExpressionException e)
|
||||||
|
{
|
||||||
|
e.printStack(source);
|
||||||
|
Messenger.m(source, "r Exception while evaluating expression at " + new BlockPos(source.getPosition()) + ": " + e.getMessage());
|
||||||
|
host.resetErrorSnooper();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ScriptHost duplicate()
|
protected ScriptHost duplicate()
|
||||||
{
|
{
|
||||||
return new CarpetScriptHost(scriptServer, this.getName(), myCode, false, this);
|
return new CarpetScriptHost(scriptServer, myCode, false, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -62,6 +98,32 @@ public class CarpetScriptHost extends ScriptHost
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ModuleInterface getModuleByName(String name)
|
||||||
|
{
|
||||||
|
ModuleInterface 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)
|
||||||
|
{
|
||||||
|
CarpetContext cc = (CarpetContext)c;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
CarpetExpression ex = new CarpetExpression(module.getCode(), cc.s, cc.origin);
|
||||||
|
ex.getExpr().asAModule(module);
|
||||||
|
ex.scriptRunCommand(this, cc.origin);
|
||||||
|
}
|
||||||
|
catch (CarpetExpressionException e) // hopefully that error got reported already
|
||||||
|
{
|
||||||
|
throw new InternalExpressionException(e.getMessage());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void delFunction(String funName)
|
public void delFunction(String funName)
|
||||||
{
|
{
|
||||||
@@ -309,4 +371,43 @@ public class CarpetScriptHost extends ScriptHost
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setChatErrorSnooper(ServerCommandSource source)
|
||||||
|
{
|
||||||
|
errorSnooper = (expr, token, message) ->
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
source.getPlayer();
|
||||||
|
}
|
||||||
|
catch (CommandSyntaxException e)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String[] lines = expr.getCodeString().split("\n");
|
||||||
|
String shebang = message;
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
shebang += " in "+expr.getName()+"";
|
||||||
|
}
|
||||||
|
Messenger.m(source, "r "+shebang);
|
||||||
|
if (lines.length > 1 && token.lineno > 0)
|
||||||
|
{
|
||||||
|
Messenger.m(source, "l "+lines[token.lineno-1]);
|
||||||
|
}
|
||||||
|
Messenger.m(source, "l "+lines[token.lineno].substring(0, token.linepos), "r HERE>> ", "l "+
|
||||||
|
lines[token.lineno].substring(token.linepos));
|
||||||
|
if (lines.length > 1 && token.lineno < lines.length-1)
|
||||||
|
{
|
||||||
|
Messenger.m(source, "l "+lines[token.lineno+1]);
|
||||||
|
}
|
||||||
|
return new ArrayList<>();
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -8,14 +8,11 @@ import carpet.CarpetSettings;
|
|||||||
import carpet.CarpetServer;
|
import carpet.CarpetServer;
|
||||||
import carpet.script.bundled.FileModule;
|
import carpet.script.bundled.FileModule;
|
||||||
import carpet.script.bundled.ModuleInterface;
|
import carpet.script.bundled.ModuleInterface;
|
||||||
import carpet.script.exception.CarpetExpressionException;
|
|
||||||
import carpet.script.exception.ExpressionException;
|
|
||||||
import carpet.script.exception.InvalidCallbackException;
|
import carpet.script.exception.InvalidCallbackException;
|
||||||
import carpet.script.value.Value;
|
import carpet.script.value.Value;
|
||||||
import carpet.utils.Messenger;
|
import carpet.utils.Messenger;
|
||||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
|
||||||
import com.mojang.brigadier.tree.CommandNode;
|
import com.mojang.brigadier.tree.CommandNode;
|
||||||
import net.minecraft.server.command.ServerCommandSource;
|
import net.minecraft.server.command.ServerCommandSource;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
@@ -51,13 +48,12 @@ public class CarpetScriptServer
|
|||||||
|
|
||||||
public CarpetScriptServer()
|
public CarpetScriptServer()
|
||||||
{
|
{
|
||||||
globalHost = createMinecraftScriptHost(null, null, false, null);
|
|
||||||
events = new CarpetEventServer();
|
events = new CarpetEventServer();
|
||||||
modules = new HashMap<>();
|
modules = new HashMap<>();
|
||||||
tickStart = 0L;
|
tickStart = 0L;
|
||||||
stopAll = false;
|
stopAll = false;
|
||||||
resetErrorSnooper();
|
|
||||||
holyMoly = CarpetServer.minecraft_server.getCommandManager().getDispatcher().getRoot().getChildren().stream().map(CommandNode::getName).collect(Collectors.toSet());
|
holyMoly = CarpetServer.minecraft_server.getCommandManager().getDispatcher().getRoot().getChildren().stream().map(CommandNode::getName).collect(Collectors.toSet());
|
||||||
|
globalHost = CarpetScriptHost.create(this, null, false, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void loadAllWorldScripts()
|
public void loadAllWorldScripts()
|
||||||
@@ -73,7 +69,7 @@ public class CarpetScriptServer
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ModuleInterface getModule(String name)
|
public ModuleInterface getModule(String name)
|
||||||
{
|
{
|
||||||
File folder = CarpetServer.minecraft_server.getLevelStorage().resolveFile(
|
File folder = CarpetServer.minecraft_server.getLevelStorage().resolveFile(
|
||||||
CarpetServer.minecraft_server.getLevelName(), "scripts");
|
CarpetServer.minecraft_server.getLevelName(), "scripts");
|
||||||
@@ -129,39 +125,6 @@ public class CarpetScriptServer
|
|||||||
return modules.get(name);
|
return modules.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private CarpetScriptHost createMinecraftScriptHost(String name, ModuleInterface module, boolean perPlayer, ServerCommandSource source)
|
|
||||||
{
|
|
||||||
CarpetScriptHost host = new CarpetScriptHost(this, name, 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)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
String code = module.getCode();
|
|
||||||
if (code == null)
|
|
||||||
{
|
|
||||||
Messenger.m(source, "r Unable to load "+name+" app - code not found");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
setChatErrorSnooper(source);
|
|
||||||
CarpetExpression ex = new CarpetExpression(code, source, new BlockPos(0, 0, 0));
|
|
||||||
ex.getExpr().asAModule();
|
|
||||||
ex.scriptRunCommand(host, new BlockPos(source.getPosition()));
|
|
||||||
}
|
|
||||||
catch (CarpetExpressionException e)
|
|
||||||
{
|
|
||||||
Messenger.m(source, "r Exception white evaluating expression at " + new BlockPos(source.getPosition()) + ": " + e.getMessage());
|
|
||||||
resetErrorSnooper();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return host;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean addScriptHost(ServerCommandSource source, String name, boolean perPlayer, boolean autoload)
|
public boolean addScriptHost(ServerCommandSource source, String name, boolean perPlayer, boolean autoload)
|
||||||
{
|
{
|
||||||
//TODO add per player modules to support player actions better on a server
|
//TODO add per player modules to support player actions better on a server
|
||||||
@@ -172,7 +135,7 @@ public class CarpetScriptServer
|
|||||||
Messenger.m(source, "r Failed to add "+name+" app");
|
Messenger.m(source, "r Failed to add "+name+" app");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
CarpetScriptHost newHost = createMinecraftScriptHost(name, module, perPlayer, source);
|
CarpetScriptHost newHost = CarpetScriptHost.create(this, module, perPlayer, source);
|
||||||
if (newHost == null)
|
if (newHost == null)
|
||||||
{
|
{
|
||||||
Messenger.m(source, "r Failed to add "+name+" app");
|
Messenger.m(source, "r Failed to add "+name+" app");
|
||||||
@@ -278,55 +241,6 @@ public class CarpetScriptServer
|
|||||||
CarpetServer.settingsManager.notifyPlayersCommandsChanged();
|
CarpetServer.settingsManager.notifyPlayersCommandsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setChatErrorSnooper(ServerCommandSource source)
|
|
||||||
{
|
|
||||||
ExpressionException.errorSnooper = (expr, token, message) ->
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
source.getPlayer();
|
|
||||||
}
|
|
||||||
catch (CommandSyntaxException e)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
String[] lines = expr.getCodeString().split("\n");
|
|
||||||
|
|
||||||
String shebang = message;
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
shebang += " in "+expr.getName()+"";
|
|
||||||
}
|
|
||||||
Messenger.m(source, "r "+shebang);
|
|
||||||
|
|
||||||
if (lines.length > 1 && token.lineno > 0)
|
|
||||||
{
|
|
||||||
Messenger.m(source, "l "+lines[token.lineno-1]);
|
|
||||||
}
|
|
||||||
Messenger.m(source, "l "+lines[token.lineno].substring(0, token.linepos), "r HERE>> ", "l "+
|
|
||||||
lines[token.lineno].substring(token.linepos));
|
|
||||||
|
|
||||||
if (lines.length > 1 && token.lineno < lines.length-1)
|
|
||||||
{
|
|
||||||
Messenger.m(source, "l "+lines[token.lineno+1]);
|
|
||||||
}
|
|
||||||
return new ArrayList<>();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public void resetErrorSnooper()
|
|
||||||
{
|
|
||||||
ExpressionException.errorSnooper=null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean removeScriptHost(ServerCommandSource source, String name)
|
public boolean removeScriptHost(ServerCommandSource source, String name)
|
||||||
{
|
{
|
||||||
name = name.toLowerCase(Locale.ROOT);
|
name = name.toLowerCase(Locale.ROOT);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import carpet.script.Fluff.QuadFunction;
|
|||||||
import carpet.script.Fluff.QuinnFunction;
|
import carpet.script.Fluff.QuinnFunction;
|
||||||
import carpet.script.Fluff.SexFunction;
|
import carpet.script.Fluff.SexFunction;
|
||||||
import carpet.script.Fluff.TriFunction;
|
import carpet.script.Fluff.TriFunction;
|
||||||
|
import carpet.script.bundled.ModuleInterface;
|
||||||
import carpet.script.exception.BreakStatement;
|
import carpet.script.exception.BreakStatement;
|
||||||
import carpet.script.exception.ContinueStatement;
|
import carpet.script.exception.ContinueStatement;
|
||||||
import carpet.script.exception.ExitStatement;
|
import carpet.script.exception.ExitStatement;
|
||||||
@@ -365,10 +366,13 @@ public class Expression implements Cloneable
|
|||||||
private boolean allowNewlineSubstitutions = true;
|
private boolean allowNewlineSubstitutions = true;
|
||||||
private boolean allowComments = false;
|
private boolean allowComments = false;
|
||||||
|
|
||||||
void asAModule()
|
public ModuleInterface module = null;
|
||||||
|
|
||||||
|
void asAModule(ModuleInterface mi)
|
||||||
{
|
{
|
||||||
allowNewlineSubstitutions = false;
|
allowNewlineSubstitutions = false;
|
||||||
allowComments = true;
|
allowComments = true;
|
||||||
|
module = mi;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
@@ -396,6 +400,7 @@ public class Expression implements Cloneable
|
|||||||
Expression copy = (Expression) super.clone();
|
Expression copy = (Expression) super.clone();
|
||||||
copy.expression = this.expression;
|
copy.expression = this.expression;
|
||||||
copy.name = this.name;
|
copy.name = this.name;
|
||||||
|
copy.module = this.module;
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -472,14 +477,14 @@ public class Expression implements Cloneable
|
|||||||
{
|
{
|
||||||
if (v2 != null)
|
if (v2 != null)
|
||||||
{
|
{
|
||||||
throw new ExpressionException(e, token, "Did not expect a second parameter for unary operator");
|
throw new ExpressionException(c, e, token, "Did not expect a second parameter for unary operator");
|
||||||
}
|
}
|
||||||
Value.assertNotNull(v);
|
Value.assertNotNull(v);
|
||||||
return lazyfun.apply(c, t, v);
|
return lazyfun.apply(c, t, v);
|
||||||
}
|
}
|
||||||
catch (RuntimeException exc)
|
catch (RuntimeException exc)
|
||||||
{
|
{
|
||||||
throw handleCodeException(exc, e, token);
|
throw handleCodeException(c, exc, e, token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -501,7 +506,7 @@ public class Expression implements Cloneable
|
|||||||
}
|
}
|
||||||
catch (RuntimeException exc)
|
catch (RuntimeException exc)
|
||||||
{
|
{
|
||||||
throw handleCodeException(exc, e, t);
|
throw handleCodeException(c, exc, e, t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -521,7 +526,7 @@ public class Expression implements Cloneable
|
|||||||
}
|
}
|
||||||
catch (RuntimeException exc)
|
catch (RuntimeException exc)
|
||||||
{
|
{
|
||||||
throw handleCodeException(exc, e, t);
|
throw handleCodeException(c, exc, e, t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -542,25 +547,25 @@ public class Expression implements Cloneable
|
|||||||
}
|
}
|
||||||
catch (RuntimeException exc)
|
catch (RuntimeException exc)
|
||||||
{
|
{
|
||||||
throw handleCodeException(exc, e, token);
|
throw handleCodeException(c, exc, e, token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static RuntimeException handleCodeException(RuntimeException exc, Expression e, Tokenizer.Token token)
|
static RuntimeException handleCodeException(Context c, RuntimeException exc, Expression e, Tokenizer.Token token)
|
||||||
{
|
{
|
||||||
if (exc instanceof ExitStatement)
|
if (exc instanceof ExitStatement)
|
||||||
return exc;
|
return exc;
|
||||||
if (exc instanceof InternalExpressionException)
|
if (exc instanceof InternalExpressionException)
|
||||||
return new ExpressionException(e, token, exc.getMessage());
|
return new ExpressionException(c, e, token, exc.getMessage(), ((InternalExpressionException) exc).stack);
|
||||||
if (exc instanceof ArithmeticException)
|
if (exc instanceof ArithmeticException)
|
||||||
return new ExpressionException(e, token, "Your math is wrong, "+exc.getMessage());
|
return new ExpressionException(c, e, token, "Your math is wrong, "+exc.getMessage());
|
||||||
if (exc instanceof ExpressionException)
|
if (exc instanceof ExpressionException)
|
||||||
return exc;
|
return exc;
|
||||||
// unexpected really - should be caught earlier and converted to InternalExpressionException
|
// unexpected really - should be caught earlier and converted to InternalExpressionException
|
||||||
exc.printStackTrace();
|
exc.printStackTrace();
|
||||||
return new ExpressionException(e, token, "Error while evaluating expression: "+exc);
|
return new ExpressionException(c, e, token, "Error while evaluating expression: "+exc);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addUnaryOperator(String surface, boolean leftAssoc, Function<Value, Value> fun)
|
private void addUnaryOperator(String surface, boolean leftAssoc, Function<Value, Value> fun)
|
||||||
@@ -659,7 +664,7 @@ public class Expression implements Cloneable
|
|||||||
}
|
}
|
||||||
catch (RuntimeException exc)
|
catch (RuntimeException exc)
|
||||||
{
|
{
|
||||||
throw handleCodeException(exc, e, t);
|
throw handleCodeException(c, exc, e, t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -668,7 +673,7 @@ public class Expression implements Cloneable
|
|||||||
{
|
{
|
||||||
name = name.toLowerCase(Locale.ROOT);
|
name = name.toLowerCase(Locale.ROOT);
|
||||||
if (functions.containsKey(name))
|
if (functions.containsKey(name))
|
||||||
throw new ExpressionException(expr, token, "Function "+name+" would mask a built-in function");
|
throw new ExpressionException(context, expr, token, "Function "+name+" would mask a built-in function");
|
||||||
Map<String, LazyValue> contextValues = new HashMap<>();
|
Map<String, LazyValue> contextValues = new HashMap<>();
|
||||||
for (String global : globals)
|
for (String global : globals)
|
||||||
{
|
{
|
||||||
@@ -684,7 +689,7 @@ public class Expression implements Cloneable
|
|||||||
}
|
}
|
||||||
if (contextValues.isEmpty()) contextValues = null;
|
if (contextValues.isEmpty()) contextValues = null;
|
||||||
|
|
||||||
FunctionValue result = new FunctionValue(expr, token, name, code, arguments, contextValues);
|
FunctionValue result = new FunctionValue(expr, token, module, name, code, arguments, contextValues);
|
||||||
// do not store lambda definitions
|
// do not store lambda definitions
|
||||||
if (!name.equals("_")) context.host.addUserDefinedFunction(name, result);
|
if (!name.equals("_")) context.host.addUserDefinedFunction(name, result);
|
||||||
return result;
|
return result;
|
||||||
@@ -861,6 +866,13 @@ public class Expression implements Cloneable
|
|||||||
public void UserDefinedFunctionsAndControlFlow() // public just to get the javadoc right
|
public void UserDefinedFunctionsAndControlFlow() // public just to get the javadoc right
|
||||||
{
|
{
|
||||||
// artificial construct to handle user defined functions and function definitions
|
// artificial construct to handle user defined functions and function definitions
|
||||||
|
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;
|
||||||
|
});
|
||||||
|
|
||||||
addLazyFunctionWithDelegation("call",-1, (c, t, expr, tok, lv) -> { // adjust based on c
|
addLazyFunctionWithDelegation("call",-1, (c, t, expr, tok, lv) -> { // adjust based on c
|
||||||
if (lv.size() == 0)
|
if (lv.size() == 0)
|
||||||
throw new InternalExpressionException("'call' expects at least function name to call");
|
throw new InternalExpressionException("'call' expects at least function name to call");
|
||||||
@@ -3129,12 +3141,12 @@ public class Expression implements Cloneable
|
|||||||
BasicDataStructures();
|
BasicDataStructures();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Tokenizer.Token> shuntingYard()
|
private List<Tokenizer.Token> shuntingYard(Context c)
|
||||||
{
|
{
|
||||||
List<Tokenizer.Token> outputQueue = new ArrayList<>();
|
List<Tokenizer.Token> outputQueue = new ArrayList<>();
|
||||||
Stack<Tokenizer.Token> stack = new Stack<>();
|
Stack<Tokenizer.Token> stack = new Stack<>();
|
||||||
|
|
||||||
Tokenizer tokenizer = new Tokenizer(this, expression, allowComments, allowNewlineSubstitutions);
|
Tokenizer tokenizer = new Tokenizer(c, this, expression, allowComments, allowNewlineSubstitutions);
|
||||||
// stripping lousy but acceptable semicolons
|
// stripping lousy but acceptable semicolons
|
||||||
List<Tokenizer.Token> cleanedTokens = tokenizer.fixSemicolons();
|
List<Tokenizer.Token> cleanedTokens = tokenizer.fixSemicolons();
|
||||||
|
|
||||||
@@ -3154,7 +3166,7 @@ public class Expression implements Cloneable
|
|||||||
previousToken.type == Tokenizer.Token.TokenType.HEX_LITERAL ||
|
previousToken.type == Tokenizer.Token.TokenType.HEX_LITERAL ||
|
||||||
previousToken.type == Tokenizer.Token.TokenType.STRINGPARAM))
|
previousToken.type == Tokenizer.Token.TokenType.STRINGPARAM))
|
||||||
{
|
{
|
||||||
throw new ExpressionException(this, token, "Missing operator");
|
throw new ExpressionException(c, this, token, "Missing operator");
|
||||||
}
|
}
|
||||||
outputQueue.add(token);
|
outputQueue.add(token);
|
||||||
break;
|
break;
|
||||||
@@ -3168,7 +3180,7 @@ public class Expression implements Cloneable
|
|||||||
case COMMA:
|
case COMMA:
|
||||||
if (previousToken != null && previousToken.type == Tokenizer.Token.TokenType.OPERATOR)
|
if (previousToken != null && previousToken.type == Tokenizer.Token.TokenType.OPERATOR)
|
||||||
{
|
{
|
||||||
throw new ExpressionException(this, previousToken, "Missing parameter(s) for operator ");
|
throw new ExpressionException(c, this, previousToken, "Missing parameter(s) for operator ");
|
||||||
}
|
}
|
||||||
while (!stack.isEmpty() && stack.peek().type != Tokenizer.Token.TokenType.OPEN_PAREN)
|
while (!stack.isEmpty() && stack.peek().type != Tokenizer.Token.TokenType.OPEN_PAREN)
|
||||||
{
|
{
|
||||||
@@ -3178,11 +3190,11 @@ public class Expression implements Cloneable
|
|||||||
{
|
{
|
||||||
if (lastFunction == null)
|
if (lastFunction == null)
|
||||||
{
|
{
|
||||||
throw new ExpressionException(this, token, "Unexpected comma");
|
throw new ExpressionException(c, this, token, "Unexpected comma");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new ExpressionException(this, lastFunction, "Parse error for function");
|
throw new ExpressionException(c, this, lastFunction, "Parse error for function");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -3191,12 +3203,12 @@ public class Expression implements Cloneable
|
|||||||
if (previousToken != null
|
if (previousToken != null
|
||||||
&& (previousToken.type == Tokenizer.Token.TokenType.COMMA || previousToken.type == Tokenizer.Token.TokenType.OPEN_PAREN))
|
&& (previousToken.type == Tokenizer.Token.TokenType.COMMA || previousToken.type == Tokenizer.Token.TokenType.OPEN_PAREN))
|
||||||
{
|
{
|
||||||
throw new ExpressionException(this, token, "Missing parameter(s) for operator '" + token+"'");
|
throw new ExpressionException(c, this, token, "Missing parameter(s) for operator '" + token+"'");
|
||||||
}
|
}
|
||||||
ILazyOperator o1 = operators.get(token.surface);
|
ILazyOperator o1 = operators.get(token.surface);
|
||||||
if (o1 == null)
|
if (o1 == null)
|
||||||
{
|
{
|
||||||
throw new ExpressionException(this, token, "Unknown operator '" + token + "'");
|
throw new ExpressionException(c, this, token, "Unknown operator '" + token + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
shuntOperators(outputQueue, stack, o1);
|
shuntOperators(outputQueue, stack, o1);
|
||||||
@@ -3208,12 +3220,12 @@ public class Expression implements Cloneable
|
|||||||
if (previousToken != null && previousToken.type != Tokenizer.Token.TokenType.OPERATOR
|
if (previousToken != null && previousToken.type != Tokenizer.Token.TokenType.OPERATOR
|
||||||
&& previousToken.type != Tokenizer.Token.TokenType.COMMA && previousToken.type != Tokenizer.Token.TokenType.OPEN_PAREN)
|
&& previousToken.type != Tokenizer.Token.TokenType.COMMA && previousToken.type != Tokenizer.Token.TokenType.OPEN_PAREN)
|
||||||
{
|
{
|
||||||
throw new ExpressionException(this, token, "Invalid position for unary operator " + token );
|
throw new ExpressionException(c, this, token, "Invalid position for unary operator " + token );
|
||||||
}
|
}
|
||||||
ILazyOperator o1 = operators.get(token.surface);
|
ILazyOperator o1 = operators.get(token.surface);
|
||||||
if (o1 == null)
|
if (o1 == null)
|
||||||
{
|
{
|
||||||
throw new ExpressionException(this, token, "Unknown unary operator '" + token.surface.substring(0, token.surface.length() - 1) + "'");
|
throw new ExpressionException(c, this, token, "Unknown unary operator '" + token.surface.substring(0, token.surface.length() - 1) + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
shuntOperators(outputQueue, stack, o1);
|
shuntOperators(outputQueue, stack, o1);
|
||||||
@@ -3245,7 +3257,7 @@ public class Expression implements Cloneable
|
|||||||
case CLOSE_PAREN:
|
case CLOSE_PAREN:
|
||||||
if (previousToken != null && previousToken.type == Tokenizer.Token.TokenType.OPERATOR)
|
if (previousToken != null && previousToken.type == Tokenizer.Token.TokenType.OPERATOR)
|
||||||
{
|
{
|
||||||
throw new ExpressionException(this, previousToken, "Missing parameter(s) for operator " + previousToken);
|
throw new ExpressionException(c, this, previousToken, "Missing parameter(s) for operator " + previousToken);
|
||||||
}
|
}
|
||||||
while (!stack.isEmpty() && stack.peek().type != Tokenizer.Token.TokenType.OPEN_PAREN)
|
while (!stack.isEmpty() && stack.peek().type != Tokenizer.Token.TokenType.OPEN_PAREN)
|
||||||
{
|
{
|
||||||
@@ -3253,7 +3265,7 @@ public class Expression implements Cloneable
|
|||||||
}
|
}
|
||||||
if (stack.isEmpty())
|
if (stack.isEmpty())
|
||||||
{
|
{
|
||||||
throw new ExpressionException("Mismatched parentheses");
|
throw new ExpressionException(c, "Mismatched parentheses");
|
||||||
}
|
}
|
||||||
stack.pop();
|
stack.pop();
|
||||||
if (!stack.isEmpty() && stack.peek().type == Tokenizer.Token.TokenType.FUNCTION)
|
if (!stack.isEmpty() && stack.peek().type == Tokenizer.Token.TokenType.FUNCTION)
|
||||||
@@ -3277,7 +3289,7 @@ public class Expression implements Cloneable
|
|||||||
Tokenizer.Token element = stack.pop();
|
Tokenizer.Token element = stack.pop();
|
||||||
if (element.type == Tokenizer.Token.TokenType.OPEN_PAREN || element.type == Tokenizer.Token.TokenType.CLOSE_PAREN)
|
if (element.type == Tokenizer.Token.TokenType.OPEN_PAREN || element.type == Tokenizer.Token.TokenType.CLOSE_PAREN)
|
||||||
{
|
{
|
||||||
throw new ExpressionException(this, element, "Mismatched parentheses");
|
throw new ExpressionException(c, this, element, "Mismatched parentheses");
|
||||||
}
|
}
|
||||||
outputQueue.add(element);
|
outputQueue.add(element);
|
||||||
}
|
}
|
||||||
@@ -3306,7 +3318,7 @@ public class Expression implements Cloneable
|
|||||||
{
|
{
|
||||||
if (ast == null)
|
if (ast == null)
|
||||||
{
|
{
|
||||||
ast = getAST();
|
ast = getAST(c);
|
||||||
}
|
}
|
||||||
return evalValue(() -> ast, c, expectedType);
|
return evalValue(() -> ast, c, expectedType);
|
||||||
}
|
}
|
||||||
@@ -3319,7 +3331,7 @@ public class Expression implements Cloneable
|
|||||||
}
|
}
|
||||||
catch (ContinueStatement | BreakStatement | ReturnStatement exc)
|
catch (ContinueStatement | BreakStatement | ReturnStatement exc)
|
||||||
{
|
{
|
||||||
throw new ExpressionException("Control flow functions, like continue, break, or return, should only be used in loops and functions respectively.");
|
throw new ExpressionException(c, "Control flow functions, like continue, break, or return, should only be used in loops and functions respectively.");
|
||||||
}
|
}
|
||||||
catch (ExitStatement exit)
|
catch (ExitStatement exit)
|
||||||
{
|
{
|
||||||
@@ -3327,23 +3339,23 @@ public class Expression implements Cloneable
|
|||||||
}
|
}
|
||||||
catch (StackOverflowError ignored)
|
catch (StackOverflowError ignored)
|
||||||
{
|
{
|
||||||
throw new ExpressionException("Your thoughts are too deep");
|
throw new ExpressionException(c, "Your thoughts are too deep");
|
||||||
}
|
}
|
||||||
catch (InternalExpressionException exc)
|
catch (InternalExpressionException exc)
|
||||||
{
|
{
|
||||||
throw new ExpressionException("Your expression result is incorrect:"+exc.getMessage());
|
throw new ExpressionException(c, "Your expression result is incorrect:"+exc.getMessage());
|
||||||
}
|
}
|
||||||
catch (ArithmeticException exc)
|
catch (ArithmeticException exc)
|
||||||
{
|
{
|
||||||
throw new ExpressionException("The final result is incorrect, "+exc.getMessage());
|
throw new ExpressionException(c, "The final result is incorrect, "+exc.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private LazyValue getAST()
|
private LazyValue getAST(Context context)
|
||||||
{
|
{
|
||||||
Stack<LazyValue> stack = new Stack<>();
|
Stack<LazyValue> stack = new Stack<>();
|
||||||
List<Tokenizer.Token> rpn = shuntingYard();
|
List<Tokenizer.Token> rpn = shuntingYard(context);
|
||||||
validate(rpn);
|
validate(context, rpn);
|
||||||
for (final Tokenizer.Token token : rpn)
|
for (final Tokenizer.Token token : rpn)
|
||||||
{
|
{
|
||||||
switch (token.type)
|
switch (token.type)
|
||||||
@@ -3415,7 +3427,7 @@ public class Expression implements Cloneable
|
|||||||
}
|
}
|
||||||
catch (NumberFormatException exception)
|
catch (NumberFormatException exception)
|
||||||
{
|
{
|
||||||
throw new ExpressionException(this, token, "Not a number");
|
throw new ExpressionException(c, this, token, "Not a number");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
@@ -3426,13 +3438,13 @@ public class Expression implements Cloneable
|
|||||||
stack.push((c, t) -> new NumericValue(new BigInteger(token.surface.substring(2), 16).doubleValue()));
|
stack.push((c, t) -> new NumericValue(new BigInteger(token.surface.substring(2), 16).doubleValue()));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ExpressionException(this, token, "Unexpected token '" + token.surface + "'");
|
throw new ExpressionException(context, this, token, "Unexpected token '" + token.surface + "'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return stack.pop();
|
return stack.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validate(List<Tokenizer.Token> rpn)
|
private void validate(Context c, List<Tokenizer.Token> rpn)
|
||||||
{
|
{
|
||||||
/*-
|
/*-
|
||||||
* Thanks to Norman Ramsey:
|
* Thanks to Norman Ramsey:
|
||||||
@@ -3454,7 +3466,7 @@ public class Expression implements Cloneable
|
|||||||
case UNARY_OPERATOR:
|
case UNARY_OPERATOR:
|
||||||
if (stack.peek() < 1)
|
if (stack.peek() < 1)
|
||||||
{
|
{
|
||||||
throw new ExpressionException(this, token, "Missing parameter(s) for operator " + token);
|
throw new ExpressionException(c, this, token, "Missing parameter(s) for operator " + token);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OPERATOR:
|
case OPERATOR:
|
||||||
@@ -3462,9 +3474,9 @@ public class Expression implements Cloneable
|
|||||||
{
|
{
|
||||||
if (token.surface.equalsIgnoreCase(";"))
|
if (token.surface.equalsIgnoreCase(";"))
|
||||||
{
|
{
|
||||||
throw new ExpressionException(this, token, "Unnecessary semicolon");
|
throw new ExpressionException(c, this, token, "Unnecessary semicolon");
|
||||||
}
|
}
|
||||||
throw new ExpressionException(this, token, "Missing parameter(s) for operator " + token);
|
throw new ExpressionException(c, this, token, "Missing parameter(s) for operator " + token);
|
||||||
}
|
}
|
||||||
// pop the operator's 2 parameters and add the result
|
// pop the operator's 2 parameters and add the result
|
||||||
stack.set(stack.size() - 1, stack.peek() - 2 + 1);
|
stack.set(stack.size() - 1, stack.peek() - 2 + 1);
|
||||||
@@ -3474,11 +3486,11 @@ public class Expression implements Cloneable
|
|||||||
int numParams = stack.pop();
|
int numParams = stack.pop();
|
||||||
if (f != null && !f.numParamsVaries() && numParams != f.getNumParams())
|
if (f != null && !f.numParamsVaries() && numParams != f.getNumParams())
|
||||||
{
|
{
|
||||||
throw new ExpressionException(this, token, "Function " + token + " expected " + f.getNumParams() + " parameters, got " + numParams);
|
throw new ExpressionException(c, this, token, "Function " + token + " expected " + f.getNumParams() + " parameters, got " + numParams);
|
||||||
}
|
}
|
||||||
if (stack.size() <= 0)
|
if (stack.size() <= 0)
|
||||||
{
|
{
|
||||||
throw new ExpressionException(this, token, "Too many function calls, maximum scope exceeded");
|
throw new ExpressionException(c, this, token, "Too many function calls, maximum scope exceeded");
|
||||||
}
|
}
|
||||||
// push the result of the function
|
// push the result of the function
|
||||||
stack.set(stack.size() - 1, stack.peek() + 1);
|
stack.set(stack.size() - 1, stack.peek() + 1);
|
||||||
@@ -3493,15 +3505,15 @@ public class Expression implements Cloneable
|
|||||||
|
|
||||||
if (stack.size() > 1)
|
if (stack.size() > 1)
|
||||||
{
|
{
|
||||||
throw new ExpressionException("Too many unhandled function parameter lists");
|
throw new ExpressionException(c, "Too many unhandled function parameter lists");
|
||||||
}
|
}
|
||||||
else if (stack.peek() > 1)
|
else if (stack.peek() > 1)
|
||||||
{
|
{
|
||||||
throw new ExpressionException("Too many numbers or variables");
|
throw new ExpressionException(c, "Too many numbers or variables");
|
||||||
}
|
}
|
||||||
else if (stack.peek() < 1)
|
else if (stack.peek() < 1)
|
||||||
{
|
{
|
||||||
throw new ExpressionException("Empty expression");
|
throw new ExpressionException(c, "Empty expression");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,16 +26,16 @@ public class ExpressionInspector
|
|||||||
return e.getName();
|
return e.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Expression Expression_cloneWithName(Expression e, String name, Tokenizer.Token token)
|
public static Expression Expression_cloneWithName(Expression e, Context c, String name, Tokenizer.Token token)
|
||||||
{
|
{
|
||||||
Expression copy = null;
|
Expression copy;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
copy = e.clone();
|
copy = e.clone();
|
||||||
}
|
}
|
||||||
catch (CloneNotSupportedException ex)
|
catch (CloneNotSupportedException ex)
|
||||||
{
|
{
|
||||||
throw new ExpressionException(e, token, "Problems in allocating global function "+name);
|
throw new ExpressionException(c, e, token, "Problems in allocating global function "+name);
|
||||||
}
|
}
|
||||||
return copy.withName(name);
|
return copy.withName(name);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ public abstract class Fluff
|
|||||||
}
|
}
|
||||||
catch (RuntimeException exc)
|
catch (RuntimeException exc)
|
||||||
{
|
{
|
||||||
throw Expression.handleCodeException(exc, e, t);
|
throw Expression.handleCodeException(cc, exc, e, t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -146,7 +146,7 @@ public abstract class Fluff
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LazyValue lazyEval(Context c_ignored, Integer type, Expression e, Tokenizer.Token t, final LazyValue v1, final LazyValue v2)
|
public LazyValue lazyEval(Context cc, Integer type, Expression e, Tokenizer.Token t, final LazyValue v1, final LazyValue v2)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -154,7 +154,7 @@ public abstract class Fluff
|
|||||||
}
|
}
|
||||||
catch (RuntimeException exc)
|
catch (RuntimeException exc)
|
||||||
{
|
{
|
||||||
throw Expression.handleCodeException(exc, e, t);
|
throw Expression.handleCodeException(cc, exc, e, t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -172,20 +172,20 @@ public abstract class Fluff
|
|||||||
{
|
{
|
||||||
if (v2 != null)
|
if (v2 != null)
|
||||||
{
|
{
|
||||||
throw new ExpressionException(e, t, "Did not expect a second parameter for unary operator");
|
throw new ExpressionException(cc, e, t, "Did not expect a second parameter for unary operator");
|
||||||
}
|
}
|
||||||
return (c, ignored_type) -> AbstractUnaryOperator.this.evalUnary(v1.evalValue(c));
|
return (c, ignored_type) -> AbstractUnaryOperator.this.evalUnary(v1.evalValue(c));
|
||||||
}
|
}
|
||||||
catch (RuntimeException exc)
|
catch (RuntimeException exc)
|
||||||
{
|
{
|
||||||
throw Expression.handleCodeException(exc, e, t);
|
throw Expression.handleCodeException(cc, exc, e, t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Value eval(Value v1, Value v2)
|
public Value eval(Value v1, Value v2)
|
||||||
{
|
{
|
||||||
throw new ExpressionException("Shouldn't end up here");
|
throw new RuntimeException("Shouldn't end up here");
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract Value evalUnary(Value v1);
|
public abstract Value evalUnary(Value v1);
|
||||||
|
|||||||
@@ -5,30 +5,36 @@ import carpet.script.value.FunctionValue;
|
|||||||
import carpet.script.value.Value;
|
import carpet.script.value.Value;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class ScriptHost
|
public abstract class ScriptHost
|
||||||
{
|
{
|
||||||
protected final Map<String, ScriptHost> userHosts = new Object2ObjectOpenHashMap<>();
|
protected final Map<String, ScriptHost> userHosts = new Object2ObjectOpenHashMap<>();
|
||||||
public Map<String, FunctionValue> globalFunctions = new Object2ObjectOpenHashMap<>();
|
public Map<String, FunctionValue> globalFunctions = new Object2ObjectOpenHashMap<>();
|
||||||
public Map<String, LazyValue> globalVariables = new Object2ObjectOpenHashMap<>();
|
public Map<String, LazyValue> globalVariables = new Object2ObjectOpenHashMap<>();
|
||||||
|
private Set<String> imports = new HashSet<>();
|
||||||
|
|
||||||
protected ScriptHost parent;
|
protected ScriptHost parent;
|
||||||
protected boolean perUser;
|
protected boolean perUser;
|
||||||
|
|
||||||
private String name;
|
//private String name;
|
||||||
public String getName() {return name;}
|
public String getName() {return myCode==null?null:myCode.getName();}
|
||||||
|
|
||||||
protected final ModuleInterface myCode;
|
protected final ModuleInterface myCode;
|
||||||
|
|
||||||
ScriptHost(String name, ModuleInterface code, boolean perUser, ScriptHost parent)
|
public Fluff.TriFunction<Expression, Tokenizer.Token, String, List<String>> errorSnooper = null;
|
||||||
|
|
||||||
|
ScriptHost(ModuleInterface code, boolean perUser, ScriptHost parent)
|
||||||
{
|
{
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.name = name;
|
//this.name = name;
|
||||||
this.myCode = code;
|
this.myCode = code;
|
||||||
this.perUser = perUser;
|
this.perUser = perUser;
|
||||||
|
if (code != null) imports.add(code.getName());
|
||||||
globalVariables.put("euler", (c, t) -> Expression.euler);
|
globalVariables.put("euler", (c, t) -> Expression.euler);
|
||||||
globalVariables.put("pi", (c, t) -> Expression.PI);
|
globalVariables.put("pi", (c, t) -> Expression.PI);
|
||||||
globalVariables.put("null", (c, t) -> Value.NULL);
|
globalVariables.put("null", (c, t) -> Value.NULL);
|
||||||
@@ -46,6 +52,24 @@ public class ScriptHost
|
|||||||
globalFunctions.put(funName, function);
|
globalFunctions.put(funName, function);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean 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))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
imports.remove(module.getName());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract ModuleInterface getModuleByName(String name); // this should be shell out in the executuor
|
||||||
|
|
||||||
|
protected abstract boolean runModuleCode(Context c, ModuleInterface module); // this should be shell out in the executuor
|
||||||
|
|
||||||
public void delFunction(String funName)
|
public void delFunction(String funName)
|
||||||
{
|
{
|
||||||
globalFunctions.remove(funName);
|
globalFunctions.remove(funName);
|
||||||
@@ -66,31 +90,20 @@ public class ScriptHost
|
|||||||
userHost = this.duplicate();
|
userHost = this.duplicate();
|
||||||
userHost.globalVariables.putAll(this.globalVariables);
|
userHost.globalVariables.putAll(this.globalVariables);
|
||||||
userHost.globalFunctions.putAll(this.globalFunctions);
|
userHost.globalFunctions.putAll(this.globalFunctions);
|
||||||
|
userHost.imports.addAll(this.imports);
|
||||||
userHosts.put(user, userHost);
|
userHosts.put(user, userHost);
|
||||||
return userHost;
|
return userHost;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ScriptHost duplicate()
|
protected abstract ScriptHost duplicate();
|
||||||
{
|
|
||||||
return new ScriptHost(this.name, myCode, false, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Expression getExpressionForFunction(String name)
|
|
||||||
{
|
|
||||||
return globalFunctions.get(name).getExpression();
|
|
||||||
}
|
|
||||||
public Tokenizer.Token getTokenForFunction(String name)
|
|
||||||
{
|
|
||||||
return globalFunctions.get(name).getToken();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getPublicFunctions()
|
public List<String> getPublicFunctions()
|
||||||
{
|
{
|
||||||
return globalFunctions.keySet().stream().filter((str) -> !str.startsWith("_")).collect(Collectors.toList());
|
return globalFunctions.keySet().stream().filter((str) -> !str.startsWith("_")).sorted().collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
public List<String> getAvailableFunctions(boolean all)
|
public List<String> getAvailableFunctions(boolean all)
|
||||||
{
|
{
|
||||||
return globalFunctions.keySet().stream().filter((str) -> all || !str.startsWith("__")).collect(Collectors.toList());
|
return globalFunctions.keySet().stream().filter((str) -> all || !str.startsWith("__")).sorted().collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onClose() { }
|
public void onClose() { }
|
||||||
@@ -99,4 +112,9 @@ public class ScriptHost
|
|||||||
{
|
{
|
||||||
perUser = isPerUser;
|
perUser = isPerUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void resetErrorSnooper()
|
||||||
|
{
|
||||||
|
errorSnooper=null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -32,11 +32,13 @@ public class Tokenizer implements Iterator<Tokenizer.Token>
|
|||||||
private Token previousToken;
|
private Token previousToken;
|
||||||
|
|
||||||
private Expression expression;
|
private Expression expression;
|
||||||
|
private Context context;
|
||||||
|
|
||||||
Tokenizer(Expression expr, String input, boolean allowComments, boolean allowNewLineMakers)
|
Tokenizer(Context c, Expression expr, String input, boolean allowComments, boolean allowNewLineMakers)
|
||||||
{
|
{
|
||||||
this.input = input;
|
this.input = input;
|
||||||
this.expression = expr;
|
this.expression = expr;
|
||||||
|
this.context = c;
|
||||||
this.comments = allowComments;
|
this.comments = allowComments;
|
||||||
this.newLinesMarkers = allowNewLineMakers;
|
this.newLinesMarkers = allowNewLineMakers;
|
||||||
}
|
}
|
||||||
@@ -89,7 +91,7 @@ public class Tokenizer implements Iterator<Tokenizer.Token>
|
|||||||
|| (ch >= 'A' && ch <= 'F');
|
|| (ch >= 'A' && ch <= 'F');
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isSemicolon(Token tok)
|
private static boolean isSemicolon(Token tok)
|
||||||
{
|
{
|
||||||
return ( tok.type == Token.TokenType.OPERATOR && tok.surface.equals(";") )
|
return ( tok.type == Token.TokenType.OPERATOR && tok.surface.equals(";") )
|
||||||
|| (tok.type == Token.TokenType.UNARY_OPERATOR && tok.surface.equals(";u") );
|
|| (tok.type == Token.TokenType.UNARY_OPERATOR && tok.surface.equals(";u") );
|
||||||
@@ -97,7 +99,7 @@ public class Tokenizer implements Iterator<Tokenizer.Token>
|
|||||||
|
|
||||||
public static List<Token> simplepass(String input)
|
public static List<Token> simplepass(String input)
|
||||||
{
|
{
|
||||||
Tokenizer tok = new Tokenizer(null, input, false, false);
|
Tokenizer tok = new Tokenizer(null, null, input, false, false);
|
||||||
List<Token> res = new ArrayList<>();
|
List<Token> res = new ArrayList<>();
|
||||||
while (tok.hasNext()) res.add(tok.next());
|
while (tok.hasNext()) res.add(tok.next());
|
||||||
return res;
|
return res;
|
||||||
@@ -157,8 +159,8 @@ public class Tokenizer implements Iterator<Tokenizer.Token>
|
|||||||
pos++;
|
pos++;
|
||||||
linepos++;
|
linepos++;
|
||||||
token.type = Token.TokenType.STRINGPARAM;
|
token.type = Token.TokenType.STRINGPARAM;
|
||||||
if (pos == input.length() && expression != null)
|
if (pos == input.length() && expression != null && context != null)
|
||||||
throw new ExpressionException(this.expression, token, "Program truncated");
|
throw new ExpressionException(context, this.expression, token, "Program truncated");
|
||||||
ch = input.charAt(pos);
|
ch = input.charAt(pos);
|
||||||
while (ch != '\'')
|
while (ch != '\'')
|
||||||
{
|
{
|
||||||
@@ -166,13 +168,13 @@ public class Tokenizer implements Iterator<Tokenizer.Token>
|
|||||||
{
|
{
|
||||||
pos++;
|
pos++;
|
||||||
linepos++;
|
linepos++;
|
||||||
if (pos == input.length() && expression != null)
|
if (pos == input.length() && expression != null && context != null)
|
||||||
throw new ExpressionException(this.expression, token, "Program truncated");
|
throw new ExpressionException(context, this.expression, token, "Program truncated");
|
||||||
}
|
}
|
||||||
token.append(input.charAt(pos++));
|
token.append(input.charAt(pos++));
|
||||||
linepos++;
|
linepos++;
|
||||||
if (pos == input.length() && expression != null)
|
if (pos == input.length() && expression != null && context != null)
|
||||||
throw new ExpressionException(this.expression, token, "Program truncated");
|
throw new ExpressionException(context, this.expression, token, "Program truncated");
|
||||||
ch = input.charAt(pos);
|
ch = input.charAt(pos);
|
||||||
}
|
}
|
||||||
pos++;
|
pos++;
|
||||||
@@ -224,12 +226,12 @@ public class Tokenizer implements Iterator<Tokenizer.Token>
|
|||||||
pos++;
|
pos++;
|
||||||
linepos++;
|
linepos++;
|
||||||
|
|
||||||
if (expression != null && previousToken != null &&
|
if (expression != null && context != null && previousToken != null &&
|
||||||
previousToken.type == Token.TokenType.OPERATOR &&
|
previousToken.type == Token.TokenType.OPERATOR &&
|
||||||
(ch == ')' || ch == ',') &&
|
(ch == ')' || ch == ',') &&
|
||||||
!previousToken.surface.equalsIgnoreCase(";")
|
!previousToken.surface.equalsIgnoreCase(";")
|
||||||
)
|
)
|
||||||
throw new ExpressionException(this.expression, previousToken,
|
throw new ExpressionException(context, this.expression, previousToken,
|
||||||
"Can't have operator " + previousToken.surface + " at the end of a subexpression");
|
"Can't have operator " + previousToken.surface + " at the end of a subexpression");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -300,7 +302,7 @@ public class Tokenizer implements Iterator<Tokenizer.Token>
|
|||||||
token.type = Token.TokenType.OPERATOR;
|
token.type = Token.TokenType.OPERATOR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (expression != null && previousToken != null &&
|
if (expression != null && context != null && previousToken != null &&
|
||||||
(
|
(
|
||||||
token.type == Token.TokenType.LITERAL ||
|
token.type == Token.TokenType.LITERAL ||
|
||||||
token.type == Token.TokenType.HEX_LITERAL ||
|
token.type == Token.TokenType.HEX_LITERAL ||
|
||||||
@@ -317,7 +319,7 @@ public class Tokenizer implements Iterator<Tokenizer.Token>
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
throw new ExpressionException(this.expression, previousToken, "'"+token.surface +"' is not allowed after '"+previousToken.surface+"'");
|
throw new ExpressionException(context, this.expression, previousToken, "'"+token.surface +"' is not allowed after '"+previousToken.surface+"'");
|
||||||
}
|
}
|
||||||
return previousToken = token;
|
return previousToken = token;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import org.apache.commons.io.IOUtils;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
public class BundledModule implements ModuleInterface
|
public class BundledModule implements ModuleInterface
|
||||||
{
|
{
|
||||||
@@ -13,9 +14,9 @@ public class BundledModule implements ModuleInterface
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
name = scriptName;
|
name = scriptName.toLowerCase(Locale.ROOT);
|
||||||
code = IOUtils.toString(
|
code = IOUtils.toString(
|
||||||
getClass().getClassLoader().getResourceAsStream("assets/carpet/scripts/"+scriptName+".sc"),
|
getClass().getClassLoader().getResourceAsStream("assets/carpet/scripts/"+name+".sc"),
|
||||||
StandardCharsets.UTF_8
|
StandardCharsets.UTF_8
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,28 @@
|
|||||||
package carpet.script.exception;
|
package carpet.script.exception;
|
||||||
|
|
||||||
public class CarpetExpressionException extends ExpressionException
|
import carpet.script.value.FunctionValue;
|
||||||
|
import carpet.utils.Messenger;
|
||||||
|
import net.minecraft.server.command.ServerCommandSource;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class CarpetExpressionException extends RuntimeException
|
||||||
{
|
{
|
||||||
public CarpetExpressionException(String message)
|
public List<FunctionValue> stack;
|
||||||
|
|
||||||
|
public CarpetExpressionException(String message, List<FunctionValue> stack)
|
||||||
{
|
{
|
||||||
super(message);
|
super(message);
|
||||||
|
this.stack = stack;
|
||||||
|
}
|
||||||
|
public void printStack(ServerCommandSource source)
|
||||||
|
{
|
||||||
|
if (stack != null && !stack.isEmpty())
|
||||||
|
{
|
||||||
|
for (FunctionValue fun : stack)
|
||||||
|
{
|
||||||
|
Messenger.m(source, "e ... in "+fun.fullName(), "e /"+(fun.getToken().lineno+1)+":"+(fun.getToken().linepos+1));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
package carpet.script.exception;
|
package carpet.script.exception;
|
||||||
|
|
||||||
|
import carpet.script.Context;
|
||||||
import carpet.script.Expression;
|
import carpet.script.Expression;
|
||||||
import carpet.script.Fluff;
|
import carpet.script.Fluff;
|
||||||
import carpet.script.Tokenizer;
|
import carpet.script.Tokenizer;
|
||||||
|
import carpet.script.value.FunctionValue;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -13,38 +15,58 @@ import static carpet.script.ExpressionInspector.Expression_getName;
|
|||||||
/* The expression evaluators exception class. */
|
/* The expression evaluators exception class. */
|
||||||
public class ExpressionException extends RuntimeException
|
public class ExpressionException extends RuntimeException
|
||||||
{
|
{
|
||||||
public ExpressionException(String message)
|
public Context context;
|
||||||
|
public List<FunctionValue> stack = new ArrayList<>();
|
||||||
|
public ExpressionException(Context c, String message)
|
||||||
{
|
{
|
||||||
super(message);
|
super(makeMessage(c, null, null, message));
|
||||||
|
context = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExpressionException(Context c, Expression e, Tokenizer.Token t, String message)
|
||||||
|
{
|
||||||
|
super(makeMessage(c, e, t, message));
|
||||||
|
context = c;
|
||||||
|
}
|
||||||
|
public ExpressionException(Context c, Expression e, Tokenizer.Token t, String message, List<FunctionValue> stack)
|
||||||
|
{
|
||||||
|
super(makeMessage(c, e, t, message));
|
||||||
|
this.stack.addAll(stack);
|
||||||
|
context = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Fluff.TriFunction<Expression, Tokenizer.Token, String, List<String>> errorMaker = (expr, token, errmessage) ->
|
private static Fluff.TriFunction<Expression, Tokenizer.Token, String, List<String>> errorMaker = (expr, token, errmessage) ->
|
||||||
{
|
{
|
||||||
|
|
||||||
List<String> snippet = Expression_getExpressionSnippet(token, expr);
|
List<String> errMsg = new ArrayList<>();
|
||||||
List<String> errMsg = new ArrayList<>(snippet);
|
if (expr != null && token != null)
|
||||||
if (snippet.size() != 1)
|
|
||||||
{
|
{
|
||||||
errmessage+= " at line "+(token.lineno+1)+", pos "+(token.linepos+1);
|
List<String> snippet = Expression_getExpressionSnippet(token, expr);
|
||||||
}
|
errMsg.addAll(snippet);
|
||||||
else
|
|
||||||
{
|
if (snippet.size() != 1)
|
||||||
errmessage += " at pos "+(token.pos+1);
|
{
|
||||||
}
|
errmessage += " at line " + (token.lineno + 1) + ", pos " + (token.linepos + 1);
|
||||||
if (Expression_getName(expr) != null)
|
}
|
||||||
{
|
else
|
||||||
errmessage += " ("+Expression_getName(expr)+")";
|
{
|
||||||
|
errmessage += " at pos " + (token.pos + 1);
|
||||||
|
}
|
||||||
|
if (Expression_getName(expr) != null)
|
||||||
|
{
|
||||||
|
errmessage += " (" + Expression_getName(expr) + ")";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
errMsg.add(errmessage);
|
errMsg.add(errmessage);
|
||||||
return errMsg;
|
return errMsg;
|
||||||
};
|
};
|
||||||
public static Fluff.TriFunction<Expression, Tokenizer.Token, String, List<String>> errorSnooper = null;
|
|
||||||
|
|
||||||
static String makeMessage(Expression e, Tokenizer.Token t, String message) throws ExpressionException
|
static String makeMessage(Context c, Expression e, Tokenizer.Token t, String message) throws ExpressionException
|
||||||
{
|
{
|
||||||
if (errorSnooper != null)
|
if (c.host.errorSnooper != null)
|
||||||
{
|
{
|
||||||
List<String> alternative = errorSnooper.apply(e, t, message);
|
List<String> alternative = c.host.errorSnooper.apply(e, t, message);
|
||||||
if (alternative!= null)
|
if (alternative!= null)
|
||||||
{
|
{
|
||||||
return String.join("\n", alternative);
|
return String.join("\n", alternative);
|
||||||
@@ -52,9 +74,4 @@ public class ExpressionException extends RuntimeException
|
|||||||
}
|
}
|
||||||
return String.join("\n", errorMaker.apply(e, t, message));
|
return String.join("\n", errorMaker.apply(e, t, message));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ExpressionException(Expression e, Tokenizer.Token t, String message)
|
|
||||||
{
|
|
||||||
super(makeMessage(e, t, message));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,14 @@
|
|||||||
package carpet.script.exception;
|
package carpet.script.exception;
|
||||||
|
|
||||||
|
import carpet.script.value.FunctionValue;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/* The internal expression evaluators exception class. */
|
/* The internal expression evaluators exception class. */
|
||||||
public class InternalExpressionException extends ExpressionException
|
public class InternalExpressionException extends RuntimeException
|
||||||
{
|
{
|
||||||
|
public List<FunctionValue> stack = new ArrayList<>();
|
||||||
public InternalExpressionException(String message)
|
public InternalExpressionException(String message)
|
||||||
{
|
{
|
||||||
super(message);
|
super(message);
|
||||||
|
|||||||
@@ -1,25 +1,23 @@
|
|||||||
package carpet.script.value;
|
package carpet.script.value;
|
||||||
|
|
||||||
import carpet.script.exception.ExpressionException;
|
|
||||||
|
|
||||||
public abstract class FrameworkValue extends Value
|
public abstract class FrameworkValue extends Value
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public String getString()
|
public String getString()
|
||||||
{
|
{
|
||||||
throw new ExpressionException("Scarpet language component cannot be used");
|
throw new UnsupportedOperationException("Scarpet language component cannot be used");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getBoolean()
|
public boolean getBoolean()
|
||||||
{
|
{
|
||||||
throw new ExpressionException("Scarpet language component cannot be used");
|
throw new UnsupportedOperationException("Scarpet language component cannot be used");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Value clone()
|
public Value clone()
|
||||||
{
|
{
|
||||||
throw new ExpressionException("Scarpet language component cannot be used");
|
throw new UnsupportedOperationException("Scarpet language component cannot be used");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import carpet.script.ExpressionInspector;
|
|||||||
import carpet.script.Fluff;
|
import carpet.script.Fluff;
|
||||||
import carpet.script.LazyValue;
|
import carpet.script.LazyValue;
|
||||||
import carpet.script.Tokenizer;
|
import carpet.script.Tokenizer;
|
||||||
|
import carpet.script.bundled.ModuleInterface;
|
||||||
import carpet.script.exception.BreakStatement;
|
import carpet.script.exception.BreakStatement;
|
||||||
import carpet.script.exception.ContinueStatement;
|
import carpet.script.exception.ContinueStatement;
|
||||||
import carpet.script.exception.ExitStatement;
|
import carpet.script.exception.ExitStatement;
|
||||||
@@ -14,6 +15,7 @@ import carpet.script.exception.InternalExpressionException;
|
|||||||
import carpet.script.exception.ReturnStatement;
|
import carpet.script.exception.ReturnStatement;
|
||||||
import carpet.script.exception.ThrowStatement;
|
import carpet.script.exception.ThrowStatement;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -22,15 +24,17 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
|
|||||||
private Expression expression;
|
private Expression expression;
|
||||||
private Tokenizer.Token token;
|
private Tokenizer.Token token;
|
||||||
private String name;
|
private String name;
|
||||||
|
private String containedPackage;
|
||||||
private LazyValue body;
|
private LazyValue body;
|
||||||
private Map<String, LazyValue> outerState;
|
private Map<String, LazyValue> outerState;
|
||||||
private List<String> args;
|
private List<String> args;
|
||||||
private static long variantCounter = 1;
|
private static long variantCounter = 1;
|
||||||
private long variant;
|
private long variant;
|
||||||
|
|
||||||
public FunctionValue(Expression expression, Tokenizer.Token token, String name, LazyValue body, List<String> args)
|
private FunctionValue(Expression expression, Tokenizer.Token token, String cpackage, String name, LazyValue body, List<String> args)
|
||||||
{
|
{
|
||||||
this.expression = expression;
|
this.expression = expression;
|
||||||
|
this.containedPackage = cpackage;
|
||||||
this.token = token;
|
this.token = token;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.body = body;
|
this.body = body;
|
||||||
@@ -39,9 +43,10 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
|
|||||||
variant = 0L;
|
variant = 0L;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FunctionValue(Expression expression, Tokenizer.Token token, String name, LazyValue body, List<String> args, Map<String, LazyValue> outerState)
|
public FunctionValue(Expression expression, Tokenizer.Token token, ModuleInterface code, String name, LazyValue body, List<String> args, Map<String, LazyValue> outerState)
|
||||||
{
|
{
|
||||||
this.expression = expression;
|
this.expression = expression;
|
||||||
|
this.containedPackage = code==null?null:code.getName();
|
||||||
this.token = token;
|
this.token = token;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.body = body;
|
this.body = body;
|
||||||
@@ -56,6 +61,8 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String fullName() {return containedPackage == null?name:name+"["+containedPackage+"]";}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getBoolean()
|
public boolean getBoolean()
|
||||||
{
|
{
|
||||||
@@ -65,7 +72,7 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
|
|||||||
@Override
|
@Override
|
||||||
protected Value clone()
|
protected Value clone()
|
||||||
{
|
{
|
||||||
FunctionValue ret = new FunctionValue(expression, token, name, body, args);
|
FunctionValue ret = new FunctionValue(expression, token, containedPackage, name, body, args);
|
||||||
ret.outerState = this.outerState;
|
ret.outerState = this.outerState;
|
||||||
ret.variant = this.variant;
|
ret.variant = this.variant;
|
||||||
return ret;
|
return ret;
|
||||||
@@ -124,19 +131,26 @@ 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)
|
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
|
// this hole thing might not be really needed (errata: needed to know the package to report with exceptions
|
||||||
Expression callContext = ExpressionInspector.Expression_cloneWithName(callingExpression, name, t);
|
Expression callContext = ExpressionInspector.Expression_cloneWithName(e, c, fullName(), t);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return lazyEval(c, type, e, t, lazyParams);
|
return lazyEval(c, type, callContext, t, lazyParams);
|
||||||
|
}
|
||||||
|
catch (ExpressionException exc)
|
||||||
|
{
|
||||||
|
exc.stack.add(this);
|
||||||
|
throw exc;
|
||||||
}
|
}
|
||||||
catch (InternalExpressionException exc)
|
catch (InternalExpressionException exc)
|
||||||
{
|
{
|
||||||
throw new ExpressionException(callContext, t, exc.getMessage());
|
exc.stack.add(this);
|
||||||
|
throw new ExpressionException(c, callContext, t, exc.getMessage(), exc.stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (ArithmeticException exc)
|
catch (ArithmeticException exc)
|
||||||
{
|
{
|
||||||
throw new ExpressionException(callContext, t, "Your math is wrong, "+exc.getMessage());
|
throw new ExpressionException(c, callContext, t, "Your math is wrong, "+exc.getMessage(), Collections.singletonList(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,7 +160,7 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
|
|||||||
if (args.size() != lazyParams.size()) // something that might be subject to change in the future
|
if (args.size() != lazyParams.size()) // something that might be subject to change in the future
|
||||||
// in case we add variable arguments
|
// in case we add variable arguments
|
||||||
{
|
{
|
||||||
throw new ExpressionException(e, t,
|
throw new ExpressionException(c, e, t,
|
||||||
"Incorrect number of arguments for function "+name+
|
"Incorrect number of arguments for function "+name+
|
||||||
". Should be "+args.size()+", not "+lazyParams.size()+" like "+args
|
". Should be "+args.size()+", not "+lazyParams.size()+" like "+args
|
||||||
);
|
);
|
||||||
@@ -168,7 +182,7 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
|
|||||||
}
|
}
|
||||||
catch (BreakStatement | ContinueStatement exc)
|
catch (BreakStatement | ContinueStatement exc)
|
||||||
{
|
{
|
||||||
throw new ExpressionException(e, t, "'continue' and 'break' can only be called inside loop function bodies");
|
throw new ExpressionException(c, e, t, "'continue' and 'break' can only be called inside loop function bodies");
|
||||||
}
|
}
|
||||||
catch (ReturnStatement returnStatement)
|
catch (ReturnStatement returnStatement)
|
||||||
{
|
{
|
||||||
@@ -179,13 +193,13 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
|
|||||||
retVal = throwStatement.retval;
|
retVal = throwStatement.retval;
|
||||||
rethrow = true;
|
rethrow = true;
|
||||||
}
|
}
|
||||||
catch (ArithmeticException | ExitStatement | ExpressionException exc)
|
catch (ArithmeticException | ExitStatement | ExpressionException | InternalExpressionException exc )
|
||||||
{
|
{
|
||||||
throw exc; // rethrow so could be contextualized if needed
|
throw exc; // rethrow so could be contextualized if needed
|
||||||
}
|
}
|
||||||
catch (Exception exc)
|
catch (Exception exc)
|
||||||
{
|
{
|
||||||
throw new ExpressionException(e, t, "Error while evaluating expression: "+exc.getMessage());
|
throw new ExpressionException(c, e, t, "Error while evaluating expression: "+exc.getMessage());
|
||||||
}
|
}
|
||||||
if (rethrow)
|
if (rethrow)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in new issue
Block a user