use of org.projectnessie.cel.interpreter.InterpretableDecorator in project cel-java by projectnessie.
the class CELTest method CustomInterpreterDecorator.
@Test
void CustomInterpreterDecorator() {
AtomicReference<Interpretable> lastInstruction = new AtomicReference<>();
InterpretableDecorator optimizeArith = i -> {
lastInstruction.set(i);
// Only optimize the instruction if it is a call.
if (!(i instanceof InterpretableCall)) {
return i;
}
InterpretableCall call = (InterpretableCall) i;
// Only optimize the math functions when they have constant arguments.
switch(call.function()) {
case "_+_":
case "_-_":
case "_*_":
case "_/_":
// These are all binary operators so they should have to arguments
Interpretable[] args = call.args();
// an empty activation and the value returns as a constant.
if (!(args[0] instanceof InterpretableConst) || !(args[1] instanceof InterpretableConst)) {
return i;
}
Val val = call.eval(emptyActivation());
if (isError(val)) {
throw new RuntimeException(val.toString());
}
return newConstValue(call.id(), val);
default:
return i;
}
};
Env env = newEnv(declarations(Decls.newVar("foo", Decls.Int)));
AstIssuesTuple astIss = env.compile("foo == -1 + 2 * 3 / 3");
env.program(astIss.getAst(), evalOptions(OptPartialEval), customDecorator(optimizeArith));
assertThat(lastInstruction.get()).isInstanceOf(InterpretableCall.class);
InterpretableCall call = (InterpretableCall) lastInstruction.get();
Interpretable[] args = call.args();
Interpretable lhs = args[0];
assertThat(lhs).isInstanceOf(InterpretableAttribute.class);
InterpretableAttribute lastAttr = (InterpretableAttribute) lhs;
NamespacedAttribute absAttr = (NamespacedAttribute) lastAttr.attr();
String[] varNames = absAttr.candidateVariableNames();
assertThat(varNames).containsExactly("foo");
Interpretable rhs = args[1];
assertThat(rhs).isInstanceOf(InterpretableConst.class);
InterpretableConst lastConst = (InterpretableConst) rhs;
// This is the last number produced by the optimization.
assertThat(lastConst.value()).isSameAs(IntOne);
}
use of org.projectnessie.cel.interpreter.InterpretableDecorator in project cel-java by projectnessie.
the class CEL method initInterpretable.
/**
* initIterpretable creates a checked or unchecked interpretable depending on whether the Ast has
* been run through the type-checker.
*/
private static Program initInterpretable(Prog p, Ast ast, List<InterpretableDecorator> decorators) {
InterpretableDecorator[] decs = decorators.toArray(new InterpretableDecorator[0]);
// slower to execute than their checked counterparts.
if (!ast.isChecked()) {
p.interpretable = p.interpreter.newUncheckedInterpretable(ast.getExpr(), decs);
return p;
}
// When the AST has been checked it contains metadata that can be used to speed up program
// execution.
CheckedExpr checked = astToCheckedExpr(ast);
p.interpretable = p.interpreter.newInterpretable(checked, decs);
return p;
}
use of org.projectnessie.cel.interpreter.InterpretableDecorator in project cel-java by projectnessie.
the class CEL method newProgram.
/**
* newProgram creates a program instance with an environment, an ast, and an optional list of
* ProgramOption values.
*
* <p>If the program cannot be configured the prog will be nil, with a non-nil error response.
*/
public static Program newProgram(Env e, Ast ast, ProgramOption... opts) {
// Build the dispatcher, interpreter, and default program value.
Dispatcher disp = newDispatcher();
// Ensure the default attribute factory is set after the adapter and provider are
// configured.
Prog p = new Prog(e, disp);
// Configure the program via the ProgramOption values.
for (ProgramOption opt : opts) {
if (opt == null) {
throw new NullPointerException("program options should be non-nil");
}
p = opt.apply(p);
if (p == null) {
throw new NullPointerException(String.format("program option of type '%s' returned null", opt.getClass().getName()));
}
}
// Set the attribute factory after the options have been set.
if (p.evalOpts.contains(EvalOption.OptPartialEval)) {
p.attrFactory = newPartialAttributeFactory(e.getContainer(), e.getTypeAdapter(), e.getTypeProvider());
} else {
p.attrFactory = newAttributeFactory(e.getContainer(), e.getTypeAdapter(), e.getTypeProvider());
}
Interpreter interp = newInterpreter(disp, e.getContainer(), e.getTypeProvider(), e.getTypeAdapter(), p.attrFactory);
p.interpreter = interp;
// Translate the EvalOption flags into InterpretableDecorator instances.
List<InterpretableDecorator> decorators = new ArrayList<>(p.decorators);
// Enable constant folding first.
if (p.evalOpts.contains(EvalOption.OptOptimize)) {
decorators.add(optimize());
}
Prog pp = p;
// Enable exhaustive eval over state tracking since it offers a superset of features.
if (p.evalOpts.contains(EvalOption.OptExhaustiveEval)) {
// State tracking requires that each Eval() call operate on an isolated EvalState
// object; hence, the presence of the factory.
ProgFactory factory = state -> {
List<InterpretableDecorator> decs = new ArrayList<>(decorators);
decs.add(exhaustiveEval(state));
Prog clone = new Prog(e, pp.evalOpts, pp.defaultVars, disp, interp, state);
return initInterpretable(clone, ast, decs);
};
return initProgGen(factory);
} else if (p.evalOpts.contains(EvalOption.OptTrackState)) {
// Enable state tracking last since it too requires the factory approach but is less
// featured than the ExhaustiveEval decorator.
ProgFactory factory = state -> {
List<InterpretableDecorator> decs = new ArrayList<>(decorators);
decs.add(trackState(state));
Prog clone = new Prog(e, pp.evalOpts, pp.defaultVars, disp, interp, state);
return initInterpretable(clone, ast, decs);
};
return initProgGen(factory);
}
return initInterpretable(p, ast, decorators);
}
Aggregations