From b412d7626fe4bcdfd66d2ab756d5e75f4ca7edaa Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Thu, 11 Apr 2024 11:15:27 -0700 Subject: [PATCH] Add CelMutableComprehension PiperOrigin-RevId: 623883065 --- .../dev/cel/common/ast/CelMutableExpr.java | 168 +++++++++++++++++- .../cel/common/ast/CelMutableExprTest.java | 133 +++++++++++++- 2 files changed, 295 insertions(+), 6 deletions(-) diff --git a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java index 09f10c330..e6362af23 100644 --- a/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java +++ b/common/src/main/java/dev/cel/common/ast/CelMutableExpr.java @@ -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); @@ -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 = ""; @@ -698,6 +708,147 @@ private CelMutableCreateMap(List 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); } @@ -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); @@ -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; @@ -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); @@ -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()); } diff --git a/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java b/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java index 612247f13..d0591cb58 100644 --- a/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java +++ b/common/src/test/java/dev/cel/common/ast/CelMutableExprTest.java @@ -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; @@ -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() @@ -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(); } @@ -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; @@ -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 @@ -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;