package carpet.script.exception; import carpet.script.Context; import carpet.script.Expression; import carpet.script.Fluff; import carpet.script.Tokenizer; import carpet.script.value.FunctionValue; import java.util.ArrayList; import java.util.List; import java.util.function.Supplier; /* The expression evaluators exception class. */ public class ExpressionException extends RuntimeException implements ResolvedException { public final Context context; public final Tokenizer.Token token; public final List stack = new ArrayList<>(); private final Supplier lazyMessage; private String cachedMessage = null; public ExpressionException(Context c, Expression e, String message) { this(c, e, Tokenizer.Token.NONE, message); } public ExpressionException(Context c, Expression e, Tokenizer.Token t, String message) { super("Error"); lazyMessage = () -> makeMessage(c, e, t, message); token = t; context = c; } public ExpressionException(Context c, Expression e, Tokenizer.Token t, String message, List stack) { super("Error"); this.stack.addAll(stack); lazyMessage = () -> makeMessage(c, e, t, message); token = t; context = c; } public ExpressionException(Context c, Expression e, Tokenizer.Token t, Supplier messageSupplier, List stack) { super("Error"); this.stack.addAll(stack); lazyMessage = () -> makeMessage(c, e, t, messageSupplier.get()); token = t; context = c; } private static final Fluff.TriFunction> errorMaker = (expr, /*Nullable*/ token, errmessage) -> { List errMsg = new ArrayList<>(); errmessage += expr.getModuleName() == null?"":(" in "+expr.getModuleName()); if (token != null) { List snippet = expr.getExpressionSnippet(token); errMsg.addAll(snippet); if (snippet.size() != 1) { errmessage += " at line " + (token.lineno + 1) + ", pos " + (token.linepos + 1); } else { errmessage += " at pos " + (token.pos + 1); } } errMsg.add(errmessage); return errMsg; }; static String makeMessage(Context c, Expression e, Tokenizer.Token t, String message) throws ExpressionException { if (c.host.errorSnooper != null) { List alternative = c.host.errorSnooper.apply(e, t, message); if (alternative!= null) { return String.join("\n", alternative); } } return String.join("\n", errorMaker.apply(e, t, message)); } @Override public String getMessage() { if (cachedMessage == null) { cachedMessage = lazyMessage.get(); } return cachedMessage; } }