Skip to content

Commit 4d114d6

Browse files
maskri17copybara-github
authored andcommitted
Checker and parser changes to support two variable comprehensions for remaining Macros
PiperOrigin-RevId: 798304931
1 parent 37828da commit 4d114d6

9 files changed

+672
-4
lines changed

checker/src/test/java/dev/cel/checker/ExprCheckerTest.java

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -793,7 +793,7 @@ public void quantifiers() throws Exception {
793793
}
794794

795795
@Test
796-
public void twoVarComprehensions() throws Exception {
796+
public void twoVarComprehensions_allMacro() throws Exception {
797797
CelType messageType = StructTypeReference.create("cel.expr.conformance.proto3.TestAllTypes");
798798
declareVariable("x", messageType);
799799
source =
@@ -805,13 +805,68 @@ public void twoVarComprehensions() throws Exception {
805805
}
806806

807807
@Test
808-
public void twoVarComprehensionsErrors() throws Exception {
808+
public void twoVarComprehensions_existsMacro() throws Exception {
809+
CelType messageType = StructTypeReference.create("cel.expr.conformance.proto3.TestAllTypes");
810+
declareVariable("x", messageType);
811+
source =
812+
"x.map_string_string.exists(i, v, i < v) "
813+
+ "&& x.repeated_int64.exists(i, v, i < v) "
814+
+ "&& [1, 2, 3, 4].exists(i, v, i < 5 && v > 0) "
815+
+ "&& {'a': 1, 'b': 2}.exists(k, v, k.startsWith('a') && v == 1)";
816+
runTest();
817+
}
818+
819+
@Test
820+
public void twoVarComprehensions_existsOneMacro() throws Exception {
821+
CelType messageType = StructTypeReference.create("cel.expr.conformance.proto3.TestAllTypes");
822+
declareVariable("x", messageType);
823+
source =
824+
"x.map_string_string.exists_one(i, v, i < v) "
825+
+ "&& x.repeated_int64.exists_one(i, v, i < v) "
826+
+ "&& [1, 2, 3, 4].exists_one(i, v, i < 5 && v > 0) "
827+
+ "&& {'a': 1, 'b': 2}.exists_one(k, v, k.startsWith('a') && v == 1)";
828+
runTest();
829+
}
830+
831+
@Test
832+
public void twoVarComprehensions_transformListMacro() throws Exception {
833+
CelType messageType = StructTypeReference.create("cel.expr.conformance.proto3.TestAllTypes");
834+
declareVariable("x", messageType);
835+
source =
836+
"[1, 2, 3].transformList(i, v, i > 0 && v < 3, (i * v) + v) == [4] "
837+
+ "&& [1, 2, 3].transformList(i, v, i % 2 == 0, (i * v) + v) == [1,9] "
838+
+ "&& [1, 2, 3].transformList(i, v, (i * v) + v) == [1,4,9]";
839+
runTest();
840+
}
841+
842+
@Test
843+
public void twoVarComprehensions_incorrectIterVars() throws Exception {
809844
CelType messageType = StructTypeReference.create("cel.expr.conformance.proto3.TestAllTypes");
810845
declareVariable("x", messageType);
811846
source = "x.map_string_string.all(i + 1, v, i < v) && x.repeated_int64.all(i, v + 1, i < v)";
812847
runTest();
813848
}
814849

850+
@Test
851+
public void twoVarComprehensions_duplicateIterVars() throws Exception {
852+
CelType messageType = StructTypeReference.create("cel.expr.conformance.proto3.TestAllTypes");
853+
declareVariable("x", messageType);
854+
source =
855+
"x.repeated_int64.exists(i, i, i < v)";
856+
runTest();
857+
}
858+
859+
@Test
860+
public void twoVarComprehensions_incorrectNumberOfArgs() throws Exception {
861+
CelType messageType = StructTypeReference.create("cel.expr.conformance.proto3.TestAllTypes");
862+
declareVariable("x", messageType);
863+
source =
864+
"[1, 2, 3, 4].exists_one(i, v, i < v, v)"
865+
+ "&& x.map_string_string.transformList(i, i < v) "
866+
+ "&& [1, 2, 3].transformList(i, v, i > 0 && x < 3, (i * v) + v) == [4]";
867+
runTest();
868+
}
869+
815870
@Test
816871
public void quantifiersErrors() throws Exception {
817872
CelType messageType = StructTypeReference.create("cel.expr.conformance.proto3.TestAllTypes");
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Source: x.repeated_int64.exists(i, i, i < v)
2+
declare x {
3+
value cel.expr.conformance.proto3.TestAllTypes
4+
}
5+
=====>
6+
ERROR: test_location:1:1: overlapping declaration name 'i' (type 'int' cannot be distinguished from 'int')
7+
| x.repeated_int64.exists(i, i, i < v)
8+
| ^
9+
ERROR: test_location:1:35: undeclared reference to 'v' (in container '')
10+
| x.repeated_int64.exists(i, i, i < v)
11+
| ..................................^
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
Source: x.map_string_string.exists(i, v, i < v) && x.repeated_int64.exists(i, v, i < v) && [1, 2, 3, 4].exists(i, v, i < 5 && v > 0) && {'a': 1, 'b': 2}.exists(k, v, k.startsWith('a') && v == 1)
2+
declare x {
3+
value cel.expr.conformance.proto3.TestAllTypes
4+
}
5+
=====>
6+
_&&_(
7+
_&&_(
8+
__comprehension__(
9+
// Variable
10+
i,
11+
v,
12+
// Target
13+
x~cel.expr.conformance.proto3.TestAllTypes^x.map_string_string~map(string, string),
14+
// Accumulator
15+
@result,
16+
// Init
17+
false~bool,
18+
// LoopCondition
19+
@not_strictly_false(
20+
!_(
21+
@result~bool^@result
22+
)~bool^logical_not
23+
)~bool^not_strictly_false,
24+
// LoopStep
25+
_||_(
26+
@result~bool^@result,
27+
_<_(
28+
i~string^i,
29+
v~string^v
30+
)~bool^less_string
31+
)~bool^logical_or,
32+
// Result
33+
@result~bool^@result)~bool,
34+
__comprehension__(
35+
// Variable
36+
i,
37+
v,
38+
// Target
39+
x~cel.expr.conformance.proto3.TestAllTypes^x.repeated_int64~list(int),
40+
// Accumulator
41+
@result,
42+
// Init
43+
false~bool,
44+
// LoopCondition
45+
@not_strictly_false(
46+
!_(
47+
@result~bool^@result
48+
)~bool^logical_not
49+
)~bool^not_strictly_false,
50+
// LoopStep
51+
_||_(
52+
@result~bool^@result,
53+
_<_(
54+
i~int^i,
55+
v~int^v
56+
)~bool^less_int64
57+
)~bool^logical_or,
58+
// Result
59+
@result~bool^@result)~bool
60+
)~bool^logical_and,
61+
_&&_(
62+
__comprehension__(
63+
// Variable
64+
i,
65+
v,
66+
// Target
67+
[
68+
1~int,
69+
2~int,
70+
3~int,
71+
4~int
72+
]~list(int),
73+
// Accumulator
74+
@result,
75+
// Init
76+
false~bool,
77+
// LoopCondition
78+
@not_strictly_false(
79+
!_(
80+
@result~bool^@result
81+
)~bool^logical_not
82+
)~bool^not_strictly_false,
83+
// LoopStep
84+
_||_(
85+
@result~bool^@result,
86+
_&&_(
87+
_<_(
88+
i~int^i,
89+
5~int
90+
)~bool^less_int64,
91+
_>_(
92+
v~int^v,
93+
0~int
94+
)~bool^greater_int64
95+
)~bool^logical_and
96+
)~bool^logical_or,
97+
// Result
98+
@result~bool^@result)~bool,
99+
__comprehension__(
100+
// Variable
101+
k,
102+
v,
103+
// Target
104+
{
105+
"a"~string:1~int,
106+
"b"~string:2~int
107+
}~map(string, int),
108+
// Accumulator
109+
@result,
110+
// Init
111+
false~bool,
112+
// LoopCondition
113+
@not_strictly_false(
114+
!_(
115+
@result~bool^@result
116+
)~bool^logical_not
117+
)~bool^not_strictly_false,
118+
// LoopStep
119+
_||_(
120+
@result~bool^@result,
121+
_&&_(
122+
k~string^k.startsWith(
123+
"a"~string
124+
)~bool^starts_with_string,
125+
_==_(
126+
v~int^v,
127+
1~int
128+
)~bool^equals
129+
)~bool^logical_and
130+
)~bool^logical_or,
131+
// Result
132+
@result~bool^@result)~bool
133+
)~bool^logical_and
134+
)~bool^logical_and
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
Source: x.map_string_string.exists_one(i, v, i < v) && x.repeated_int64.exists_one(i, v, i < v) && [1, 2, 3, 4].exists_one(i, v, i < 5 && v > 0) && {'a': 1, 'b': 2}.exists_one(k, v, k.startsWith('a') && v == 1)
2+
declare x {
3+
value cel.expr.conformance.proto3.TestAllTypes
4+
}
5+
=====>
6+
_&&_(
7+
_&&_(
8+
__comprehension__(
9+
// Variable
10+
i,
11+
v,
12+
// Target
13+
x~cel.expr.conformance.proto3.TestAllTypes^x.map_string_string~map(string, string),
14+
// Accumulator
15+
@result,
16+
// Init
17+
0~int,
18+
// LoopCondition
19+
true~bool,
20+
// LoopStep
21+
_?_:_(
22+
_<_(
23+
i~string^i,
24+
v~string^v
25+
)~bool^less_string,
26+
_+_(
27+
@result~int^@result,
28+
1~int
29+
)~int^add_int64,
30+
@result~int^@result
31+
)~int^conditional,
32+
// Result
33+
_==_(
34+
@result~int^@result,
35+
1~int
36+
)~bool^equals)~bool,
37+
__comprehension__(
38+
// Variable
39+
i,
40+
v,
41+
// Target
42+
x~cel.expr.conformance.proto3.TestAllTypes^x.repeated_int64~list(int),
43+
// Accumulator
44+
@result,
45+
// Init
46+
0~int,
47+
// LoopCondition
48+
true~bool,
49+
// LoopStep
50+
_?_:_(
51+
_<_(
52+
i~int^i,
53+
v~int^v
54+
)~bool^less_int64,
55+
_+_(
56+
@result~int^@result,
57+
1~int
58+
)~int^add_int64,
59+
@result~int^@result
60+
)~int^conditional,
61+
// Result
62+
_==_(
63+
@result~int^@result,
64+
1~int
65+
)~bool^equals)~bool
66+
)~bool^logical_and,
67+
_&&_(
68+
__comprehension__(
69+
// Variable
70+
i,
71+
v,
72+
// Target
73+
[
74+
1~int,
75+
2~int,
76+
3~int,
77+
4~int
78+
]~list(int),
79+
// Accumulator
80+
@result,
81+
// Init
82+
0~int,
83+
// LoopCondition
84+
true~bool,
85+
// LoopStep
86+
_?_:_(
87+
_&&_(
88+
_<_(
89+
i~int^i,
90+
5~int
91+
)~bool^less_int64,
92+
_>_(
93+
v~int^v,
94+
0~int
95+
)~bool^greater_int64
96+
)~bool^logical_and,
97+
_+_(
98+
@result~int^@result,
99+
1~int
100+
)~int^add_int64,
101+
@result~int^@result
102+
)~int^conditional,
103+
// Result
104+
_==_(
105+
@result~int^@result,
106+
1~int
107+
)~bool^equals)~bool,
108+
__comprehension__(
109+
// Variable
110+
k,
111+
v,
112+
// Target
113+
{
114+
"a"~string:1~int,
115+
"b"~string:2~int
116+
}~map(string, int),
117+
// Accumulator
118+
@result,
119+
// Init
120+
0~int,
121+
// LoopCondition
122+
true~bool,
123+
// LoopStep
124+
_?_:_(
125+
_&&_(
126+
k~string^k.startsWith(
127+
"a"~string
128+
)~bool^starts_with_string,
129+
_==_(
130+
v~int^v,
131+
1~int
132+
)~bool^equals
133+
)~bool^logical_and,
134+
_+_(
135+
@result~int^@result,
136+
1~int
137+
)~int^add_int64,
138+
@result~int^@result
139+
)~int^conditional,
140+
// Result
141+
_==_(
142+
@result~int^@result,
143+
1~int
144+
)~bool^equals)~bool
145+
)~bool^logical_and
146+
)~bool^logical_and

0 commit comments

Comments
 (0)