Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 163 additions & 5 deletions common/src/main/java/dev/cel/common/ast/CelMutableExpr.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ public CelMutableCreateMap createMap() {
return (CelMutableCreateMap) exprValue;
}

public CelMutableComprehension comprehension() {
checkExprKind(Kind.COMPREHENSION);
return (CelMutableComprehension) exprValue;
}

public void setConstant(CelConstant constant) {
this.exprKind = ExprKind.Kind.CONSTANT;
this.exprValue = checkNotNull(constant);
Expand Down Expand Up @@ -128,6 +133,11 @@ public void setCreateMap(CelMutableCreateMap createMap) {
this.exprValue = checkNotNull(createMap);
}

public void setComprehension(CelMutableComprehension comprehension) {
this.exprKind = ExprKind.Kind.COMPREHENSION;
this.exprValue = checkNotNull(comprehension);
}

/** A mutable identifier expression. */
public static final class CelMutableIdent {
private String name = "";
Expand Down Expand Up @@ -698,6 +708,147 @@ private CelMutableCreateMap(List<CelMutableCreateMap.Entry> entries) {
}
}

/** A mutable comprehension expression applied to a list or map. */
public static final class CelMutableComprehension {

private String iterVar;

private CelMutableExpr iterRange;

private String accuVar;

private CelMutableExpr accuInit;

private CelMutableExpr loopCondition;

private CelMutableExpr loopStep;

private CelMutableExpr result;

public String iterVar() {
return iterVar;
}

public void setIterVar(String iterVar) {
this.iterVar = checkNotNull(iterVar);
}

public CelMutableExpr iterRange() {
return iterRange;
}

public void setIterRange(CelMutableExpr iterRange) {
this.iterRange = checkNotNull(iterRange);
}

public String accuVar() {
return accuVar;
}

public void setAccuVar(String accuVar) {
this.accuVar = checkNotNull(accuVar);
}

public CelMutableExpr accuInit() {
return accuInit;
}

public void setAccuInit(CelMutableExpr accuInit) {
this.accuInit = checkNotNull(accuInit);
}

public CelMutableExpr loopCondition() {
return loopCondition;
}

public void setLoopCondition(CelMutableExpr loopCondition) {
this.loopCondition = checkNotNull(loopCondition);
}

public CelMutableExpr loopStep() {
return loopStep;
}

public void setLoopStep(CelMutableExpr loopStep) {
this.loopStep = checkNotNull(loopStep);
}

public CelMutableExpr result() {
return result;
}

public void setResult(CelMutableExpr result) {
this.result = checkNotNull(result);
}

@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof CelMutableComprehension) {
CelMutableComprehension that = (CelMutableComprehension) obj;
return this.iterVar.equals(that.iterVar())
&& this.accuVar.equals(that.accuVar())
&& this.iterRange.equals(that.iterRange())
&& this.accuInit.equals(that.accuInit())
&& this.loopCondition.equals(that.loopCondition())
&& this.loopStep.equals(that.loopStep())
&& this.result.equals(that.result());
}
return false;
}

@Override
public int hashCode() {
int h = 1;
h *= 1000003;
h ^= iterVar.hashCode();
h *= 1000003;
h ^= iterRange.hashCode();
h *= 1000003;
h ^= accuVar.hashCode();
h *= 1000003;
h ^= accuInit.hashCode();
h *= 1000003;
h ^= loopCondition.hashCode();
h *= 1000003;
h ^= loopStep.hashCode();
h *= 1000003;
h ^= result.hashCode();
return h;
}

public static CelMutableComprehension create(
String iterVar,
CelMutableExpr iterRange,
String accuVar,
CelMutableExpr accuInit,
CelMutableExpr loopCondition,
CelMutableExpr loopStep,
CelMutableExpr result) {
return new CelMutableComprehension(
iterVar, iterRange, accuVar, accuInit, loopCondition, loopStep, result);
}

private CelMutableComprehension(
String iterVar,
CelMutableExpr iterRange,
String accuVar,
CelMutableExpr accuInit,
CelMutableExpr loopCondition,
CelMutableExpr loopStep,
CelMutableExpr result) {
this.iterVar = checkNotNull(iterVar);
this.iterRange = checkNotNull(iterRange);
this.accuVar = checkNotNull(accuVar);
this.accuInit = checkNotNull(accuInit);
this.loopCondition = checkNotNull(loopCondition);
this.loopStep = checkNotNull(loopStep);
this.result = checkNotNull(result);
}
}

public static CelMutableExpr ofNotSet() {
return ofNotSet(0L);
}
Expand Down Expand Up @@ -762,6 +913,11 @@ public static CelMutableExpr ofCreateMap(long id, CelMutableCreateMap mutableCre
return new CelMutableExpr(id, mutableCreateMap);
}

public static CelMutableExpr ofComprehension(
long id, CelMutableComprehension mutableComprehension) {
return new CelMutableExpr(id, mutableComprehension);
}

private CelMutableExpr(long id, CelConstant mutableConstant) {
this.id = id;
setConstant(mutableConstant);
Expand Down Expand Up @@ -797,6 +953,11 @@ private CelMutableExpr(long id, CelMutableCreateMap mutableCreateMap) {
setCreateMap(mutableCreateMap);
}

private CelMutableExpr(long id, CelMutableComprehension mutableComprehension) {
this.id = id;
setComprehension(mutableComprehension);
}

private CelMutableExpr(long id) {
this();
this.id = id;
Expand Down Expand Up @@ -826,7 +987,7 @@ private Object exprValue() {
case CREATE_MAP:
return createMap();
case COMPREHENSION:
// fall-through (not implemented yet)
return comprehension();
}

throw new IllegalStateException("Unexpected expr kind: " + this.exprKind);
Expand All @@ -846,10 +1007,7 @@ public boolean equals(Object obj) {
if (this.id != that.id() || !this.exprKind.equals(that.getKind())) {
return false;
}
// When both objects' hashes are cached and they do not match, they can never be equal.
if (this.hash != 0 && that.hash != 0 && this.hash != that.hash) {
return false;
}

return this.exprValue().equals(that.exprValue());
}

Expand Down
133 changes: 132 additions & 1 deletion common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
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.CelMutableComprehension;
import dev.cel.common.ast.CelMutableExpr.CelMutableCreateList;
import dev.cel.common.ast.CelMutableExpr.CelMutableCreateMap;
import dev.cel.common.ast.CelMutableExpr.CelMutableCreateStruct;
Expand Down Expand Up @@ -449,6 +450,73 @@ public void mutableCreateMapEntry_setters() {
true));
}

@Test
public void ofComprehension_withId() {
CelMutableExpr mutableExpr =
CelMutableExpr.ofComprehension(
10L,
CelMutableComprehension.create(
"iterVar",
CelMutableExpr.ofCreateList(
CelMutableCreateList.create(
CelMutableExpr.ofConstant(CelConstant.ofValue(true)))),
"accuVar",
CelMutableExpr.ofConstant(CelConstant.ofValue(true)),
CelMutableExpr.ofConstant(CelConstant.ofValue(true)),
CelMutableExpr.ofConstant(CelConstant.ofValue(true)),
CelMutableExpr.ofIdent("__result__")));

assertThat(mutableExpr.id()).isEqualTo(10L);
assertThat(mutableExpr.comprehension())
.isEqualTo(
CelMutableComprehension.create(
"iterVar",
CelMutableExpr.ofCreateList(
CelMutableCreateList.create(
CelMutableExpr.ofConstant(CelConstant.ofValue(true)))),
"accuVar",
CelMutableExpr.ofConstant(CelConstant.ofValue(true)),
CelMutableExpr.ofConstant(CelConstant.ofValue(true)),
CelMutableExpr.ofConstant(CelConstant.ofValue(true)),
CelMutableExpr.ofIdent("__result__")));
}

@Test
public void mutableComprehension_setters() {
CelMutableComprehension mutableComprehension =
CelMutableComprehension.create(
"iterVar",
CelMutableExpr.ofNotSet(),
"accuVar",
CelMutableExpr.ofNotSet(),
CelMutableExpr.ofNotSet(),
CelMutableExpr.ofNotSet(),
CelMutableExpr.ofNotSet());

mutableComprehension.setIterVar("iterVar2");
mutableComprehension.setAccuVar("accuVar2");
mutableComprehension.setIterRange(
CelMutableExpr.ofCreateList(
CelMutableCreateList.create(CelMutableExpr.ofConstant(CelConstant.ofValue(true)))));
mutableComprehension.setAccuInit(CelMutableExpr.ofConstant(CelConstant.ofValue(true)));
mutableComprehension.setLoopCondition(CelMutableExpr.ofConstant(CelConstant.ofValue(true)));
mutableComprehension.setLoopStep(CelMutableExpr.ofConstant(CelConstant.ofValue(true)));
mutableComprehension.setResult(CelMutableExpr.ofIdent("__result__"));

assertThat(mutableComprehension)
.isEqualTo(
CelMutableComprehension.create(
"iterVar2",
CelMutableExpr.ofCreateList(
CelMutableCreateList.create(
CelMutableExpr.ofConstant(CelConstant.ofValue(true)))),
"accuVar2",
CelMutableExpr.ofConstant(CelConstant.ofValue(true)),
CelMutableExpr.ofConstant(CelConstant.ofValue(true)),
CelMutableExpr.ofConstant(CelConstant.ofValue(true)),
CelMutableExpr.ofIdent("__result__")));
}

@Test
public void equalityTest() {
new EqualsTester()
Expand Down Expand Up @@ -534,6 +602,42 @@ public void equalityTest() {
CelMutableExpr.ofConstant(CelConstant.ofValue("key")),
CelMutableExpr.ofConstant(CelConstant.ofValue("value")),
/* optionalEntry= */ true))))
.addEqualityGroup(
CelMutableExpr.ofComprehension(
10L,
CelMutableComprehension.create(
"iterVar",
CelMutableExpr.ofNotSet(),
"accuVar",
CelMutableExpr.ofNotSet(),
CelMutableExpr.ofNotSet(),
CelMutableExpr.ofNotSet(),
CelMutableExpr.ofNotSet())))
.addEqualityGroup(
CelMutableExpr.ofComprehension(
11L,
CelMutableComprehension.create(
"iterVar",
CelMutableExpr.ofCreateList(
CelMutableCreateList.create(
CelMutableExpr.ofConstant(CelConstant.ofValue(true)))),
"accuVar",
CelMutableExpr.ofConstant(CelConstant.ofValue(true)),
CelMutableExpr.ofConstant(CelConstant.ofValue(true)),
CelMutableExpr.ofConstant(CelConstant.ofValue(true)),
CelMutableExpr.ofIdent("__result__"))),
CelMutableExpr.ofComprehension(
11L,
CelMutableComprehension.create(
"iterVar",
CelMutableExpr.ofCreateList(
CelMutableCreateList.create(
CelMutableExpr.ofConstant(CelConstant.ofValue(true)))),
"accuVar",
CelMutableExpr.ofConstant(CelConstant.ofValue(true)),
CelMutableExpr.ofConstant(CelConstant.ofValue(true)),
CelMutableExpr.ofConstant(CelConstant.ofValue(true)),
CelMutableExpr.ofIdent("__result__"))))
.testEquals();
}

Expand All @@ -549,6 +653,17 @@ private enum MutableExprKindTestCase {
CelMutableExpr.ofCreateStruct(
CelMutableCreateStruct.create("message", ImmutableList.of()))),
CREATE_MAP(CelMutableExpr.ofCreateMap(CelMutableCreateMap.create(ImmutableList.of()))),
COMPREHENSION(
CelMutableExpr.ofComprehension(
10L,
CelMutableComprehension.create(
"iterVar",
CelMutableExpr.ofNotSet(),
"accuVar",
CelMutableExpr.ofNotSet(),
CelMutableExpr.ofNotSet(),
CelMutableExpr.ofNotSet(),
CelMutableExpr.ofNotSet()))),
;

private final CelMutableExpr mutableExpr;
Expand Down Expand Up @@ -585,6 +700,9 @@ public void getExprValue_invalidKind_throws(@TestParameter MutableExprKindTestCa
if (!testCaseKind.equals(Kind.CREATE_MAP)) {
assertThrows(IllegalArgumentException.class, testCase.mutableExpr::createMap);
}
if (!testCaseKind.equals(Kind.COMPREHENSION)) {
assertThrows(IllegalArgumentException.class, testCase.mutableExpr::comprehension);
}
}

@SuppressWarnings("Immutable") // Mutable by design
Expand Down Expand Up @@ -635,7 +753,20 @@ private enum HashCodeTestCase {
CelMutableExpr.ofConstant(CelConstant.ofValue("value")),
/* optionalEntry= */ true)))),
1260717292),
;
COMPREHENSION(
CelMutableExpr.ofComprehension(
10L,
CelMutableComprehension.create(
"iterVar",
CelMutableExpr.ofCreateList(
CelMutableCreateList.create(
CelMutableExpr.ofConstant(CelConstant.ofValue(true)))),
"accuVar",
CelMutableExpr.ofConstant(CelConstant.ofValue(true)),
CelMutableExpr.ofConstant(CelConstant.ofValue(true)),
CelMutableExpr.ofConstant(CelConstant.ofValue(true)),
CelMutableExpr.ofIdent("__result__"))),
-1006359408);

private final CelMutableExpr mutableExpr;
private final int expectedHashCode;
Expand Down