Skip to content

Commit

Permalink
Create an enum for functions used in CelOptionalLibrary
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 609107977
  • Loading branch information
l46kok authored and copybara-github committed Feb 21, 2024
1 parent a740bbd commit 1e12305
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 31 deletions.
49 changes: 32 additions & 17 deletions extensions/src/main/java/dev/cel/extensions/CelOptionalLibrary.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,26 @@
public final class CelOptionalLibrary implements CelCompilerLibrary, CelRuntimeLibrary {
public static final CelOptionalLibrary INSTANCE = new CelOptionalLibrary();

private static final String VALUE_FUNCTION = "value";
private static final String HAS_VALUE_FUNCTION = "hasValue";
private static final String OPTIONAL_NONE_FUNCTION = "optional.none";
private static final String OPTIONAL_OF_FUNCTION = "optional.of";
private static final String OPTIONAL_OF_NON_ZERO_VALUE_FUNCTION = "optional.ofNonZeroValue";
/** Enumerations of function names used for supporting optionals. */
public enum Function {
VALUE("value"),
HAS_VALUE("hasValue"),
OPTIONAL_NONE("optional.none"),
OPTIONAL_OF("optional.of"),
OPTIONAL_OF_NON_ZERO_VALUE("optional.ofNonZeroValue"),
OR("or"),
OR_VALUE("orValue");
private final String functionName;

public String getFunction() {
return functionName;
}

Function(String functionName) {
this.functionName = functionName;
}
}

private static final String UNUSED_ITER_VAR = "#unused";

@Override
Expand All @@ -80,20 +95,20 @@ public void setCheckerOptions(CelCheckerBuilder checkerBuilder) {
MapType mapTypeKv = MapType.create(paramTypeK, paramTypeV);
checkerBuilder.addFunctionDeclarations(
CelFunctionDecl.newFunctionDeclaration(
OPTIONAL_OF_FUNCTION,
Function.OPTIONAL_OF.getFunction(),
CelOverloadDecl.newGlobalOverload("optional_of", optionalTypeV, paramTypeV)),
CelFunctionDecl.newFunctionDeclaration(
OPTIONAL_OF_NON_ZERO_VALUE_FUNCTION,
Function.OPTIONAL_OF_NON_ZERO_VALUE.getFunction(),
CelOverloadDecl.newGlobalOverload(
"optional_ofNonZeroValue", optionalTypeV, paramTypeV)),
CelFunctionDecl.newFunctionDeclaration(
OPTIONAL_NONE_FUNCTION,
Function.OPTIONAL_NONE.getFunction(),
CelOverloadDecl.newGlobalOverload("optional_none", optionalTypeV)),
CelFunctionDecl.newFunctionDeclaration(
VALUE_FUNCTION,
Function.VALUE.getFunction(),
CelOverloadDecl.newMemberOverload("optional_value", paramTypeV, optionalTypeV)),
CelFunctionDecl.newFunctionDeclaration(
HAS_VALUE_FUNCTION,
Function.HAS_VALUE.getFunction(),
CelOverloadDecl.newMemberOverload("optional_hasValue", SimpleType.BOOL, optionalTypeV)),
// Note: Implementation of "or" and "orValue" are special-cased inside the interpreter.
// Hence, their bindings are not provided here.
Expand Down Expand Up @@ -218,18 +233,18 @@ private static Optional<CelExpr> expandOptMap(
return Optional.of(
exprFactory.newGlobalCall(
Operator.CONDITIONAL.getFunction(),
exprFactory.newReceiverCall(HAS_VALUE_FUNCTION, target),
exprFactory.newReceiverCall(Function.HAS_VALUE.getFunction(), target),
exprFactory.newGlobalCall(
OPTIONAL_OF_FUNCTION,
Function.OPTIONAL_OF.getFunction(),
exprFactory.fold(
UNUSED_ITER_VAR,
exprFactory.newList(),
varName,
exprFactory.newReceiverCall(VALUE_FUNCTION, target),
exprFactory.newReceiverCall(Function.VALUE.getFunction(), target),
exprFactory.newBoolLiteral(true),
exprFactory.newIdentifier(varName),
mapExpr)),
exprFactory.newGlobalCall(OPTIONAL_NONE_FUNCTION)));
exprFactory.newGlobalCall(Function.OPTIONAL_NONE.getFunction())));
}

private static Optional<CelExpr> expandOptFlatMap(
Expand All @@ -252,16 +267,16 @@ private static Optional<CelExpr> expandOptFlatMap(
return Optional.of(
exprFactory.newGlobalCall(
Operator.CONDITIONAL.getFunction(),
exprFactory.newReceiverCall(HAS_VALUE_FUNCTION, target),
exprFactory.newReceiverCall(Function.HAS_VALUE.getFunction(), target),
exprFactory.fold(
UNUSED_ITER_VAR,
exprFactory.newList(),
varName,
exprFactory.newReceiverCall(VALUE_FUNCTION, target),
exprFactory.newReceiverCall(Function.VALUE.getFunction(), target),
exprFactory.newBoolLiteral(true),
exprFactory.newIdentifier(varName),
mapExpr),
exprFactory.newGlobalCall(OPTIONAL_NONE_FUNCTION)));
exprFactory.newGlobalCall(Function.OPTIONAL_NONE.getFunction())));
}

private CelOptionalLibrary() {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ java_library(
"//common/ast",
"//common/ast:expr_util",
"//common/navigation",
"//extensions:optional_library",
"//optimizer:ast_optimizer",
"//optimizer:mutable_ast",
"//optimizer:optimization_exception",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import dev.cel.common.ast.CelExprUtil;
import dev.cel.common.navigation.CelNavigableAst;
import dev.cel.common.navigation.CelNavigableExpr;
import dev.cel.extensions.CelOptionalLibrary.Function;
import dev.cel.optimizer.CelAstOptimizer;
import dev.cel.optimizer.CelOptimizationException;
import dev.cel.optimizer.MutableAst;
Expand Down Expand Up @@ -68,10 +69,9 @@ public static ConstantFoldingOptimizer newInstance(

// Use optional.of and optional.none as sentinel function names for folding optional calls.
// TODO: Leverage CelValue representation of Optionals instead when available.
private static final String OPTIONAL_OF_FUNCTION = "optional.of";
private static final String OPTIONAL_NONE_FUNCTION = "optional.none";
private static final CelExpr OPTIONAL_NONE_EXPR =
CelExpr.ofCallExpr(0, Optional.empty(), OPTIONAL_NONE_FUNCTION, ImmutableList.of());
CelExpr.ofCallExpr(
0, Optional.empty(), Function.OPTIONAL_NONE.getFunction(), ImmutableList.of());

private final ConstantFoldingOptions constantFoldingOptions;
private final MutableAst mutableAst;
Expand Down Expand Up @@ -130,8 +130,8 @@ private static boolean canFold(CelNavigableExpr navigableExpr) {
String functionName = celCall.function();

// These are already folded or do not need to be folded.
if (functionName.equals(OPTIONAL_OF_FUNCTION)
|| functionName.equals(OPTIONAL_NONE_FUNCTION)) {
if (functionName.equals(Function.OPTIONAL_OF.getFunction())
|| functionName.equals(Function.OPTIONAL_NONE.getFunction())) {
return false;
}

Expand Down Expand Up @@ -264,13 +264,13 @@ private Optional<CelExpr> maybeAdaptEvaluatedResult(Object result) {
private Optional<CelAbstractSyntaxTree> maybeRewriteOptional(
Optional<?> optResult, CelAbstractSyntaxTree ast, CelExpr expr) {
if (!optResult.isPresent()) {
if (!expr.callOrDefault().function().equals(OPTIONAL_NONE_FUNCTION)) {
if (!expr.callOrDefault().function().equals(Function.OPTIONAL_NONE.getFunction())) {
// An empty optional value was encountered. Rewrite the tree with optional.none call.
// This is to account for other optional functions returning an empty optional value
// e.g: optional.ofNonZeroValue(0)
return Optional.of(mutableAst.replaceSubtree(ast, OPTIONAL_NONE_EXPR, expr.id()));
}
} else if (!expr.callOrDefault().function().equals(OPTIONAL_OF_FUNCTION)) {
} else if (!expr.callOrDefault().function().equals(Function.OPTIONAL_OF.getFunction())) {
Object unwrappedResult = optResult.get();
if (!CelConstant.isConstantValue(unwrappedResult)) {
// Evaluated result is not a constant. Leave the optional as is.
Expand All @@ -281,7 +281,7 @@ private Optional<CelAbstractSyntaxTree> maybeRewriteOptional(
CelExpr.newBuilder()
.setCall(
CelCall.newBuilder()
.setFunction(OPTIONAL_OF_FUNCTION)
.setFunction(Function.OPTIONAL_OF.getFunction())
.addArgs(
CelExpr.newBuilder()
.setConstant(CelConstant.ofObjectValue(unwrappedResult))
Expand Down Expand Up @@ -444,12 +444,12 @@ private CelAbstractSyntaxTree pruneOptionalListElements(CelAbstractSyntaxTree as

if (element.exprKind().getKind().equals(Kind.CALL)) {
CelCall call = element.call();
if (call.function().equals(OPTIONAL_NONE_FUNCTION)) {
if (call.function().equals(Function.OPTIONAL_NONE.getFunction())) {
// Skip optional.none.
// Skipping causes the list to get smaller.
newOptIndex--;
continue;
} else if (call.function().equals(OPTIONAL_OF_FUNCTION)) {
} else if (call.function().equals(Function.OPTIONAL_OF.getFunction())) {
CelExpr arg = call.args().get(0);
if (arg.exprKind().getKind().equals(Kind.CONSTANT)) {
updatedElemBuilder.add(call.args().get(0));
Expand Down Expand Up @@ -491,11 +491,11 @@ private CelAbstractSyntaxTree pruneOptionalMapElements(CelAbstractSyntaxTree ast
}

CelCall call = value.call();
if (call.function().equals(OPTIONAL_NONE_FUNCTION)) {
if (call.function().equals(Function.OPTIONAL_NONE.getFunction())) {
// Skip the element. This is resolving an optional.none: ex {?1: optional.none()}.
modified = true;
continue;
} else if (call.function().equals(OPTIONAL_OF_FUNCTION)) {
} else if (call.function().equals(Function.OPTIONAL_OF.getFunction())) {
CelExpr arg = call.args().get(0);
if (arg.exprKind().getKind().equals(Kind.CONSTANT)) {
modified = true;
Expand Down Expand Up @@ -537,11 +537,11 @@ private CelAbstractSyntaxTree pruneOptionalStructElements(
}

CelCall call = value.call();
if (call.function().equals(OPTIONAL_NONE_FUNCTION)) {
if (call.function().equals(Function.OPTIONAL_NONE.getFunction())) {
// Skip the element. This is resolving an optional.none: ex msg{?field: optional.none()}.
modified = true;
continue;
} else if (call.function().equals(OPTIONAL_OF_FUNCTION)) {
} else if (call.function().equals(Function.OPTIONAL_OF.getFunction())) {
CelExpr arg = call.args().get(0);
if (arg.exprKind().getKind().equals(Kind.CONSTANT)) {
modified = true;
Expand Down

0 comments on commit 1e12305

Please sign in to comment.