com.g2forge.alexandria.expression.eval.LoggingEvaluator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ax-expression Show documentation
Show all versions of ax-expression Show documentation
A library for expressions and their evaluation. Includes a basic implementation for math.
package com.g2forge.alexandria.expression.eval;
import java.util.function.Consumer;
import java.util.function.Supplier;
import com.g2forge.alexandria.expression.ExpressionNotEvaluableException;
import com.g2forge.alexandria.expression.IEnvironment;
import com.g2forge.alexandria.expression.IExpression;
import com.g2forge.alexandria.expression.IVariable;
import com.g2forge.alexandria.java.close.ICloseable;
import com.g2forge.alexandria.java.function.IFunction2;
import com.g2forge.alexandria.java.nestedstate.FlagState;
import com.g2forge.alexandria.java.nestedstate.INestedState;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class LoggingEvaluator, N extends IEnvironment, E extends IExpression> implements IEvaluator {
protected final INestedState debug = new FlagState();
protected int nesting = 0;
@Override
public E apply(E expression, N environment, Supplier supplier) {
return log(getHeaderApply(null, expression, environment), supplier);
}
@Override
public E apply(String description, E expression, N environment) {
return log(description, getHeaderApply(description, expression, environment), () -> expression.apply(environment));
}
@Override
public ICloseable debug() {
return debug.open(true);
}
@Override
public L eval(E expression, Class type, Supplier supplier) throws ExpressionNotEvaluableException {
return log(getHeaderEval(null, expression), supplier);
}
protected Consumer getHeaderApply(String description, E expression, N environment) {
return prefix -> {
if (description != null) log.debug("{}Apply {}", prefix, description);
else log.debug("{}Apply", prefix);
log.debug("{} {}", prefix, environment);
log.debug("{} {}", prefix, expression);
};
}
protected Consumer getHeaderEval(String description, E expression) {
return prefix -> {
if (description != null) log.debug("{}Eval {} {}", prefix, description, expression);
else log.debug("{}Eval {}", prefix, expression);
};
}
protected Consumer getHeaderReduce(String description, E expression) {
return prefix -> {
if (description != null) log.debug("{}Reduce {} {}", prefix, description, expression);
else log.debug("{}Reduce {}", prefix, expression);
};
}
protected String getPrefix() {
if (nesting == 0) return "";
return new String(new char[nesting * 2]).replace('\0', ' ');
}
public T log(Consumer header, Supplier supplier) {
if (debug.get() || (nesting > 0)) return supplier.get();
header.accept("");
nesting++;
T retVal = null;
try {
retVal = supplier.get();
} finally {
nesting--;
log.debug("->{}", retVal);
}
return retVal;
}
public T log(String description, Consumer header, Supplier> supplier) {
if (debug.get()) {
@SuppressWarnings("unchecked")
final T retVal = (T) supplier.get();
return retVal;
}
final String prefix = getPrefix();
header.accept(prefix);
nesting++;
T retVal = null;
try {
@SuppressWarnings("unchecked")
final T cast = (T) supplier.get();
retVal = cast;
} finally {
nesting--;
log.debug("{}->{}", prefix, retVal);
}
return retVal;
}
@Override
public E reduce(E expression, Supplier supplier) {
return log(getHeaderReduce(null, expression), supplier);
}
@Override
public E reduce(String description, E expression) {
return log(description, getHeaderReduce(description, expression), () -> expression.reduce());
}
@Override
public T eval(String description, E expression, Class type, IFunction2 super E, ? super Class, ? extends T> function) throws ExpressionNotEvaluableException {
return log(description, getHeaderEval(description, expression), () -> function.apply(expression, type));
}
}