Skip to content

Commit

Permalink
Add CelMutableCall
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 623630568
  • Loading branch information
l46kok authored and copybara-github committed Apr 10, 2024
1 parent facc16e commit d7b7a30
Show file tree
Hide file tree
Showing 2 changed files with 277 additions and 0 deletions.
134 changes: 134 additions & 0 deletions common/src/main/java/dev/cel/common/ast/CelMutableExpr.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
import dev.cel.common.ast.CelExpr.CelNotSet;
import dev.cel.common.ast.CelExpr.ExprKind;
import dev.cel.common.ast.CelExpr.ExprKind.Kind;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Optional;

/**
* An abstract representation of a common expression that allows mutation in any of its properties.
Expand All @@ -37,6 +42,7 @@ public final class CelMutableExpr {
private CelConstant constant;
private CelMutableIdent ident;
private CelMutableSelect select;
private CelMutableCall call;
private int hash = 0;

public long id() {
Expand Down Expand Up @@ -71,6 +77,11 @@ public CelMutableSelect select() {
return select;
}

public CelMutableCall call() {
checkExprKind(Kind.CALL);
return call;
}

public void setConstant(CelConstant constant) {
this.exprKind = ExprKind.Kind.CONSTANT;
this.constant = checkNotNull(constant);
Expand All @@ -86,6 +97,11 @@ public void setSelect(CelMutableSelect select) {
this.select = checkNotNull(select);
}

public void setCall(CelMutableCall call) {
this.exprKind = ExprKind.Kind.CALL;
this.call = checkNotNull(call);
}

/** A mutable identifier expression. */
public static final class CelMutableIdent {
private String name = "";
Expand Down Expand Up @@ -196,6 +212,110 @@ private CelMutableSelect(CelMutableExpr operand, String field, boolean testOnly)
}
}

/** A mutable call expression, including calls to predefined functions and operators. */
public static final class CelMutableCall {
private Optional<CelMutableExpr> target;
private String function;
private List<CelMutableExpr> args;

public Optional<CelMutableExpr> target() {
return target;
}

public void setTarget(CelMutableExpr target) {
this.target = Optional.of(target);
}

public String function() {
return function;
}

public void setFunction(String function) {
this.function = checkNotNull(function);
}

public List<CelMutableExpr> args() {
return args;
}

public void clearArgs() {
args.clear();
}

public void addArgs(CelMutableExpr... exprs) {
addArgs(Arrays.asList(checkNotNull(exprs)));
}

public void addArgs(Iterable<CelMutableExpr> exprs) {
exprs.forEach(e -> args.add(checkNotNull(e)));
}

public void setArgs(Collection<CelMutableExpr> exprs) {
this.args = new ArrayList<>(checkNotNull(exprs));
}

public void setArg(int index, CelMutableExpr arg) {
checkArgument(index >= 0 && index < args.size());
args.set(index, checkNotNull(arg));
}

@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof CelMutableCall) {
CelMutableCall that = (CelMutableCall) obj;
return this.target.equals(that.target())
&& this.function.equals(that.function())
&& this.args.equals(that.args());
}

return false;
}

@Override
public int hashCode() {
int h = 1;
h *= 1000003;
h ^= target.hashCode();
h *= 1000003;
h ^= function.hashCode();
h *= 1000003;
h ^= args.hashCode();
return h;
}

public static CelMutableCall create(String function, CelMutableExpr... args) {
return create(function, Arrays.asList(checkNotNull(args)));
}

public static CelMutableCall create(String function, List<CelMutableExpr> args) {
return new CelMutableCall(function, args);
}

public static CelMutableCall create(
CelMutableExpr target, String function, CelMutableExpr... args) {
return create(target, function, Arrays.asList(checkNotNull(args)));
}

public static CelMutableCall create(
CelMutableExpr target, String function, List<CelMutableExpr> args) {
return new CelMutableCall(target, function, args);
}

private CelMutableCall(String function, List<CelMutableExpr> args) {
this.target = Optional.empty();
this.function = checkNotNull(function);
this.args = new ArrayList<>(checkNotNull(args));
}

private CelMutableCall(CelMutableExpr target, String function, List<CelMutableExpr> args) {
this(function, args);
this.target = Optional.of(target);
}
}

public static CelMutableExpr ofNotSet() {
return ofNotSet(0L);
}
Expand Down Expand Up @@ -228,6 +348,14 @@ public static CelMutableExpr ofSelect(long id, CelMutableSelect mutableSelect) {
return new CelMutableExpr(id, mutableSelect);
}

public static CelMutableExpr ofCall(CelMutableCall mutableCall) {
return ofCall(0, mutableCall);
}

public static CelMutableExpr ofCall(long id, CelMutableCall mutableCall) {
return new CelMutableExpr(id, mutableCall);
}

private CelMutableExpr(long id, CelConstant mutableConstant) {
this.id = id;
setConstant(mutableConstant);
Expand All @@ -243,6 +371,11 @@ private CelMutableExpr(long id, CelMutableSelect mutableSelect) {
setSelect(mutableSelect);
}

private CelMutableExpr(long id, CelMutableCall mutableCall) {
this.id = id;
setCall(mutableCall);
}

private CelMutableExpr(long id) {
this();
this.id = id;
Expand All @@ -264,6 +397,7 @@ private Object exprValue() {
case SELECT:
return select();
case CALL:
return call();
case CREATE_LIST:
case CREATE_STRUCT:
case CREATE_MAP:
Expand Down
143 changes: 143 additions & 0 deletions common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,15 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;

import com.google.common.collect.ImmutableList;
import com.google.common.testing.EqualsTester;
import com.google.testing.junit.testparameterinjector.TestParameter;
import com.google.testing.junit.testparameterinjector.TestParameterInjector;
import dev.cel.common.ast.CelExpr.ExprKind.Kind;
import dev.cel.common.ast.CelMutableExpr.CelMutableCall;
import dev.cel.common.ast.CelMutableExpr.CelMutableIdent;
import dev.cel.common.ast.CelMutableExpr.CelMutableSelect;
import java.util.ArrayList;
import org.junit.Test;
import org.junit.runner.RunWith;

Expand Down Expand Up @@ -124,6 +127,41 @@ public void mutableSelect_setters() {
assertThat(select.testOnly()).isFalse();
}

@Test
public void ofCall() {
CelMutableExpr mutableExpr =
CelMutableExpr.ofCall(
CelMutableCall.create(
CelMutableExpr.ofConstant(CelConstant.ofValue("target")),
"function",
CelMutableExpr.ofConstant(CelConstant.ofValue("arg"))));

assertThat(mutableExpr.id()).isEqualTo(0L);
assertThat(mutableExpr.call().target())
.hasValue(CelMutableExpr.ofConstant(CelConstant.ofValue("target")));
assertThat(mutableExpr.call().function()).isEqualTo("function");
assertThat(mutableExpr.call().args())
.containsExactly(CelMutableExpr.ofConstant(CelConstant.ofValue("arg")));
}

@Test
public void ofCall_withId() {
CelMutableExpr mutableExpr =
CelMutableExpr.ofCall(
1L,
CelMutableCall.create(
CelMutableExpr.ofConstant(CelConstant.ofValue("target")),
"function",
CelMutableExpr.ofConstant(CelConstant.ofValue("arg"))));

assertThat(mutableExpr.id()).isEqualTo(1L);
assertThat(mutableExpr.call().target())
.hasValue(CelMutableExpr.ofConstant(CelConstant.ofValue("target")));
assertThat(mutableExpr.call().function()).isEqualTo("function");
assertThat(mutableExpr.call().args())
.containsExactly(CelMutableExpr.ofConstant(CelConstant.ofValue("arg")));
}

@Test
public void setId_success() {
CelMutableExpr mutableExpr = CelMutableExpr.ofConstant(CelConstant.ofValue(5L));
Expand All @@ -133,6 +171,85 @@ public void setId_success() {
assertThat(mutableExpr.id()).isEqualTo(2L);
}

@Test
public void mutableCall_setArgumentAtIndex() {
CelMutableCall call =
CelMutableCall.create("function", CelMutableExpr.ofConstant(CelConstant.ofValue(1L)));

call.setArg(0, CelMutableExpr.ofConstant(CelConstant.ofValue("hello")));

assertThat(call.args())
.containsExactly(CelMutableExpr.ofConstant(CelConstant.ofValue("hello")));
assertThat(call.args()).isInstanceOf(ArrayList.class);
}

@Test
public void mutableCall_setArguments() {
CelMutableCall call =
CelMutableCall.create("function", CelMutableExpr.ofConstant(CelConstant.ofValue(1L)));

call.setArgs(
ImmutableList.of(
CelMutableExpr.ofConstant(CelConstant.ofValue(2)),
CelMutableExpr.ofConstant(CelConstant.ofValue(3))));

assertThat(call.args())
.containsExactly(
CelMutableExpr.ofConstant(CelConstant.ofValue(2)),
CelMutableExpr.ofConstant(CelConstant.ofValue(3)))
.inOrder();
assertThat(call.args()).isInstanceOf(ArrayList.class);
}

@Test
public void mutableCall_addArguments() {
CelMutableCall call =
CelMutableCall.create("function", CelMutableExpr.ofConstant(CelConstant.ofValue(1L)));

call.addArgs(
CelMutableExpr.ofConstant(CelConstant.ofValue(2)),
CelMutableExpr.ofConstant(CelConstant.ofValue(3)));

assertThat(call.args())
.containsExactly(
CelMutableExpr.ofConstant(CelConstant.ofValue(1)),
CelMutableExpr.ofConstant(CelConstant.ofValue(2)),
CelMutableExpr.ofConstant(CelConstant.ofValue(3)))
.inOrder();
assertThat(call.args()).isInstanceOf(ArrayList.class);
}

@Test
public void mutableCall_clearArguments() {
CelMutableCall call =
CelMutableCall.create(
"function",
CelMutableExpr.ofConstant(CelConstant.ofValue(1L)),
CelMutableExpr.ofConstant(CelConstant.ofValue(2L)));

call.clearArgs();

assertThat(call.args()).isEmpty();
}

@Test
public void mutableCall_setTarget() {
CelMutableCall call = CelMutableCall.create("function");

call.setTarget(CelMutableExpr.ofConstant(CelConstant.ofValue("hello")));

assertThat(call.target()).hasValue(CelMutableExpr.ofConstant(CelConstant.ofValue("hello")));
}

@Test
public void mutableCall_setFunction() {
CelMutableCall call = CelMutableCall.create("function");

call.setFunction("function2");

assertThat(call.function()).isEqualTo("function2");
}

@Test
public void equalityTest() {
new EqualsTester()
Expand All @@ -151,6 +268,20 @@ public void equalityTest() {
4L, CelMutableSelect.create(CelMutableExpr.ofIdent("x"), "test")),
CelMutableExpr.ofSelect(
4L, CelMutableSelect.create(CelMutableExpr.ofIdent("x"), "test")))
.addEqualityGroup(CelMutableExpr.ofCall(CelMutableCall.create("function")))
.addEqualityGroup(
CelMutableExpr.ofCall(
5L,
CelMutableCall.create(
CelMutableExpr.ofConstant(CelConstant.ofValue("target")),
"function",
CelMutableExpr.ofConstant(CelConstant.ofValue("arg")))),
CelMutableExpr.ofCall(
5L,
CelMutableCall.create(
CelMutableExpr.ofConstant(CelConstant.ofValue("target")),
"function",
CelMutableExpr.ofConstant(CelConstant.ofValue("arg")))))
.testEquals();
}

Expand All @@ -160,6 +291,7 @@ private enum MutableExprKindTestCase {
CONSTANT(CelMutableExpr.ofConstant(CelConstant.ofValue(2L))),
IDENT(CelMutableExpr.ofIdent("test")),
SELECT(CelMutableExpr.ofSelect(CelMutableSelect.create(CelMutableExpr.ofNotSet(), "field"))),
CALL(CelMutableExpr.ofCall(CelMutableCall.create("call"))),
;

private final CelMutableExpr mutableExpr;
Expand All @@ -184,6 +316,9 @@ public void getExprValue_invalidKind_throws(@TestParameter MutableExprKindTestCa
if (!testCaseKind.equals(Kind.SELECT)) {
assertThrows(IllegalArgumentException.class, testCase.mutableExpr::select);
}
if (!testCaseKind.equals(Kind.CALL)) {
assertThrows(IllegalArgumentException.class, testCase.mutableExpr::call);
}
}

@SuppressWarnings("Immutable") // Mutable by design
Expand All @@ -196,6 +331,14 @@ private enum HashCodeTestCase {
4L,
CelMutableSelect.create(CelMutableExpr.ofIdent("y"), "field", /* testOnly= */ true)),
1458249843),
CALL(
CelMutableExpr.ofCall(
5L,
CelMutableCall.create(
CelMutableExpr.ofConstant(CelConstant.ofValue("target")),
"function",
CelMutableExpr.ofConstant(CelConstant.ofValue("arg")))),
-1735261193),
;

private final CelMutableExpr mutableExpr;
Expand Down

0 comments on commit d7b7a30

Please sign in to comment.