From f21897fab1f35c073ac46a5c067bf0c36682ad51 Mon Sep 17 00:00:00 2001 From: gnembon Date: Sat, 22 May 2021 01:21:20 -0300 Subject: [PATCH] added custom context to be used in optimization evaluations that should expose all programmers issues, while allowing reporting errors to the error snooping entity. Fixes #875 --- src/main/java/carpet/script/Context.java | 60 +++++++++++++++++++ src/main/java/carpet/script/Expression.java | 15 ++--- src/main/java/carpet/script/ScriptHost.java | 7 ++- .../script/exception/ExpressionException.java | 4 +- 4 files changed, 76 insertions(+), 10 deletions(-) diff --git a/src/main/java/carpet/script/Context.java b/src/main/java/carpet/script/Context.java index 17bcd2c6..748da050 100644 --- a/src/main/java/carpet/script/Context.java +++ b/src/main/java/carpet/script/Context.java @@ -1,5 +1,6 @@ package carpet.script; +import carpet.script.exception.InternalExpressionException; import carpet.script.value.Value; import java.util.HashMap; @@ -83,4 +84,63 @@ public class Context { return new Context(this.host); } + public ScriptHost.ErrorSnooper getErrorSnooper() + { + return host.errorSnooper; + } + + + /** + * immutable context only for reason on reporting access violations in evaluating expressions in optimizization + * mode detecting any potential violations that may happen on the way + */ + public static class ContextForErrorReporting extends Context + { + public ScriptHost.ErrorSnooper optmizerEerrorSnooper; + public ContextForErrorReporting(Context parent) + { + super(null); + optmizerEerrorSnooper = parent.host.errorSnooper; + } + + @Override + public ScriptHost.ErrorSnooper getErrorSnooper() + { + return optmizerEerrorSnooper; + } + + public void badProgrammer() + { + throw new InternalExpressionException("Attempting to access the execution context while optimizing the code;" + + " This is not the problem with your code, but the error cause by improper use of code compile optimizations" + + "of scarpet authors. Please report this issue directly to the scarpet issue tracker"); + + } + @Override + public LazyValue getVariable(String name) { badProgrammer(); return null;} + + @Override + public void setVariable(String name, LazyValue lv) { badProgrammer(); } + + @Override + public void delVariable(String variable) { badProgrammer(); } + + @Override + public void removeVariablesMatching(String varname) { badProgrammer(); } + + @Override + public Context with(String variable, LazyValue lv) { badProgrammer(); return this; } + + @Override + public Set getAllVariableNames() { badProgrammer(); return null;} + + @Override + public Context recreate() { badProgrammer(); return null;} + + @Override + protected void initialize() { badProgrammer();} + + @Override + public Context duplicate() { badProgrammer(); return null;} + } } diff --git a/src/main/java/carpet/script/Expression.java b/src/main/java/carpet/script/Expression.java index 2f33ecc2..b1a62fcc 100644 --- a/src/main/java/carpet/script/Expression.java +++ b/src/main/java/carpet/script/Expression.java @@ -1072,6 +1072,7 @@ public class Expression if (!CarpetSettings.scriptsOptimization) return root.op; + Context optimizeOnlyContext = new Context.ContextForErrorReporting(context); CarpetScriptServer.LOG.info("Input code size for "+getModuleName()+": " + treeSize(root) + " nodes, " + treeDepth(root) + " deep"); boolean changed = true; @@ -1088,13 +1089,13 @@ public class Expression while (true) { int tree_size = treeSize(root); int tree_depth = treeDepth(root); - boolean optimized = optimizeTree(context, root, Context.Type.NONE, 0); + boolean optimized = optimizeTree(optimizeOnlyContext, root, Context.Type.NONE, 0); if (!optimized) break; changed = true; CarpetScriptServer.LOG.info("Optimized from " + tree_size + " nodes, " + tree_depth + " code depth to " + treeSize(root) + " nodes, " + treeDepth(root) + " code depth"); } } - return extractOp(context, root, Context.Type.NONE); + return extractOp(optimizeOnlyContext, root, Context.Type.NONE); } private int treeSize(ExpressionNode node) @@ -1222,25 +1223,25 @@ public class Expression Value val = ((LazyValue.Constant) arg.op).get(); args.add((c, t) -> val); } - else args.add((c, t) -> arg.op.evalValue(null, requestedType)); + else args.add((c, t) -> arg.op.evalValue(ctx, requestedType)); } catch (NullPointerException npe) { throw new ExpressionException(ctx, this, node.token, "Attempted to evaluate context free expression"); } } // applying argument unpacking - args= AbstractLazyFunction.lazify(AbstractLazyFunction.unpackLazy(args, null, requestedType)); + args= AbstractLazyFunction.lazify(AbstractLazyFunction.unpackLazy(args, ctx, requestedType)); Value result; if (operation instanceof ILazyFunction) { - result = ((ILazyFunction) operation).lazyEval(null, expectedType, this, node.token, args).evalValue(null, expectedType); + result = ((ILazyFunction) operation).lazyEval(ctx, expectedType, this, node.token, args).evalValue(null, expectedType); } else if (args.size() == 1) { - result = ((ILazyOperator)operation).lazyEval(null, expectedType, this, node.token, args.get(0), null).evalValue(null, expectedType); + result = ((ILazyOperator)operation).lazyEval(ctx, expectedType, this, node.token, args.get(0), null).evalValue(null, expectedType); } else // args == 2 { - result = ((ILazyOperator)operation).lazyEval(null, expectedType, this, node.token, args.get(0), args.get(1)).evalValue(null, expectedType); + result = ((ILazyOperator)operation).lazyEval(ctx, expectedType, this, node.token, args.get(0), args.get(1)).evalValue(null, expectedType); } node.op = LazyValue.ofConstant(result); //node.token.morph(Tokenizer.Token.TokenType.CONSTANT, node.token.surface); diff --git a/src/main/java/carpet/script/ScriptHost.java b/src/main/java/carpet/script/ScriptHost.java index 150cc0ea..919e0ced 100644 --- a/src/main/java/carpet/script/ScriptHost.java +++ b/src/main/java/carpet/script/ScriptHost.java @@ -105,7 +105,12 @@ public abstract class ScriptHost public final Module main; - public Fluff.TriFunction> errorSnooper = null; + @FunctionalInterface + public interface ErrorSnooper + { + List apply(Expression expression, Tokenizer.Token token, String message); + } + public ErrorSnooper errorSnooper = null; protected ScriptHost(Module code, boolean perUser, ScriptHost parent) { diff --git a/src/main/java/carpet/script/exception/ExpressionException.java b/src/main/java/carpet/script/exception/ExpressionException.java index b0872d05..7e494b1d 100644 --- a/src/main/java/carpet/script/exception/ExpressionException.java +++ b/src/main/java/carpet/script/exception/ExpressionException.java @@ -72,9 +72,9 @@ public class ExpressionException extends RuntimeException implements ResolvedExc synchronized static String makeMessage(Context c, Expression e, Tokenizer.Token t, String message) throws ExpressionException { - if (c.host.errorSnooper != null) + if (c.getErrorSnooper() != null) { - List alternative = c.host.errorSnooper.apply(e, t, message); + List alternative = c.getErrorSnooper().apply(e, t, message); if (alternative!= null) { return String.join("\n", alternative);