use of com.google.api.expr.v1alpha1.Expr.Call in project cel-java by projectnessie.
the class Unparser method visitCallBinary.
void visitCallBinary(Call expr) {
String fun = expr.getFunction();
List<Expr> args = expr.getArgsList();
Expr lhs = args.get(0);
// add parens if the current operator is lower precedence than the lhs expr operator.
boolean lhsParen = isComplexOperatorWithRespectTo(fun, lhs);
Expr rhs = args.get(1);
// add parens if the current operator is lower precedence than the rhs expr operator,
// or the same precedence and the operator is left recursive.
boolean rhsParen = isComplexOperatorWithRespectTo(fun, rhs);
if (!rhsParen && isLeftRecursive(fun)) {
rhsParen = isSamePrecedence(Operator.precedence(fun), rhs);
}
visitMaybeNested(lhs, lhsParen);
String unmangled = Operator.findReverseBinaryOperator(fun);
if (unmangled == null) {
throw new IllegalStateException(String.format("cannot unmangle operator: %s", fun));
}
str.append(" ");
str.append(unmangled);
str.append(" ");
visitMaybeNested(rhs, rhsParen);
}
use of com.google.api.expr.v1alpha1.Expr.Call 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 com.google.api.expr.v1alpha1.Expr.Call in project cel-java by projectnessie.
the class AstPruner method maybePruneConditional.
Expr maybePruneConditional(Expr node) {
if (!existsWithUnknownValue(node.getId())) {
return null;
}
Call call = node.getCallExpr();
Val condVal = value(call.getArgs(0).getId());
if (condVal == null || isUnknownOrError(condVal)) {
return null;
}
if (condVal == True) {
return call.getArgs(1);
}
return call.getArgs(2);
}
use of com.google.api.expr.v1alpha1.Expr.Call in project cel-java by projectnessie.
the class AstPruner method prune.
Expr prune(Expr node) {
if (node == null) {
return null;
}
Val val = value(node.getId());
if (val != null && !isUnknownOrError(val)) {
Expr newNode = maybeCreateLiteral(node.getId(), val);
if (newNode != null) {
return newNode;
}
}
switch(node.getExprKindCase()) {
case SELECT_EXPR:
Select select = node.getSelectExpr();
Expr operand = prune(select.getOperand());
if (operand != null && operand != select.getOperand()) {
return Expr.newBuilder().setId(node.getId()).setSelectExpr(Select.newBuilder().setOperand(operand).setField(select.getField()).setTestOnly(select.getTestOnly())).build();
}
break;
case CALL_EXPR:
Call call = node.getCallExpr();
Expr newExpr = maybePruneFunction(node);
if (newExpr != null) {
newExpr = prune(newExpr);
return newExpr;
}
boolean prunedCall = false;
List<Expr> args = call.getArgsList();
List<Expr> newArgs = new ArrayList<>(args.size());
for (int i = 0; i < args.size(); i++) {
Expr arg = args.get(i);
newArgs.add(arg);
Expr newArg = prune(arg);
if (newArg != null && newArg != arg) {
prunedCall = true;
newArgs.set(i, newArg);
}
}
Call newCall = Call.newBuilder().setFunction(call.getFunction()).setTarget(call.getTarget()).addAllArgs(newArgs).build();
Expr newTarget = prune(call.getTarget());
if (newTarget != null && newTarget != call.getTarget()) {
prunedCall = true;
newCall = Call.newBuilder().setFunction(call.getFunction()).setTarget(newTarget).addAllArgs(newArgs).build();
}
if (prunedCall) {
return Expr.newBuilder().setId(node.getId()).setCallExpr(newCall).build();
}
break;
case LIST_EXPR:
CreateList list = node.getListExpr();
List<Expr> elems = list.getElementsList();
List<Expr> newElems = new ArrayList<>(elems.size());
boolean prunedList = false;
for (int i = 0; i < elems.size(); i++) {
Expr elem = elems.get(i);
newElems.add(elem);
Expr newElem = prune(elem);
if (newElem != null && newElem != elem) {
newElems.set(i, newElem);
prunedList = true;
}
}
if (prunedList) {
return Expr.newBuilder().setId(node.getId()).setListExpr(CreateList.newBuilder().addAllElements(newElems)).build();
}
break;
case STRUCT_EXPR:
boolean prunedStruct = false;
CreateStruct struct = node.getStructExpr();
List<Entry> entries = struct.getEntriesList();
String messageType = struct.getMessageName();
List<Entry> newEntries = new ArrayList<>(entries.size());
for (int i = 0; i < entries.size(); i++) {
Entry entry = entries.get(i);
newEntries.add(entry);
Expr mapKey = entry.getMapKey();
Expr newKey = mapKey != Entry.getDefaultInstance().getMapKey() ? prune(mapKey) : null;
Expr newValue = prune(entry.getValue());
if ((newKey == null || newKey == mapKey) && (newValue == null || newValue == entry.getValue())) {
continue;
}
prunedStruct = true;
Entry newEntry;
if (!messageType.isEmpty()) {
newEntry = Entry.newBuilder().setFieldKey(entry.getFieldKey()).setValue(newValue).build();
} else {
newEntry = Entry.newBuilder().setMapKey(newKey).setValue(newValue).build();
}
newEntries.set(i, newEntry);
}
if (prunedStruct) {
return Expr.newBuilder().setId(node.getId()).setStructExpr(CreateStruct.newBuilder().setMessageName(messageType).addAllEntries(entries)).build();
}
break;
case COMPREHENSION_EXPR:
Comprehension compre = node.getComprehensionExpr();
// Only the range of the comprehension is pruned since the state tracking only records
// the last iteration of the comprehension and not each step in the evaluation which
// means that the any residuals computed in between might be inaccurate.
Expr newRange = prune(compre.getIterRange());
if (newRange != null && newRange != compre.getIterRange()) {
return Expr.newBuilder().setId(node.getId()).setComprehensionExpr(Comprehension.newBuilder().setIterVar(compre.getIterVar()).setIterRange(newRange).setAccuVar(compre.getAccuVar()).setAccuInit(compre.getAccuInit()).setLoopCondition(compre.getLoopCondition()).setLoopStep(compre.getLoopStep()).setResult(compre.getResult())).build();
}
}
// allocation cost at another point. So go with the simple approach - at least for now.
return node;
}
use of com.google.api.expr.v1alpha1.Expr.Call in project cel-java by projectnessie.
the class ConformanceServerTest method fullPipeline.
/**
* fullPipeline parses, checks, and evaluates the CEL expression in source and returns the result
* from the Eval call.
*/
FullPipelineResult fullPipeline(String source) {
// Parse
ParseRequest preq = ParseRequest.newBuilder().setCelSource(source).build();
ParseResponse pres = stub.parse(preq);
assertThat(pres.isInitialized()).isTrue();
ParsedExpr parsedExpr = pres.getParsedExpr();
assertThat(parsedExpr.isInitialized()).isTrue();
assertThat(parsedExpr.getExpr().isInitialized()).isTrue();
// Check
CheckRequest creq = CheckRequest.newBuilder().setParsedExpr(parsedExpr).build();
CheckResponse cres = stub.check(creq);
assertThat(cres.isInitialized()).isTrue();
CheckedExpr checkedExpr = cres.getCheckedExpr();
assertThat(checkedExpr.isInitialized()).isTrue();
// Eval
EvalRequest ereq = EvalRequest.newBuilder().setCheckedExpr(checkedExpr).build();
EvalResponse eres = stub.eval(ereq);
assertThat(eres.isInitialized()).isTrue();
assertThat(eres.getResult().isInitialized()).isTrue();
return new FullPipelineResult(pres, cres, eres);
}
Aggregations