Skip to content

Commit ece46c4

Browse files
jnthntatumcopybara-github
authored andcommitted
Add option to enable updated accumulator variable.
PiperOrigin-RevId: 707977249
1 parent 4e6761c commit ece46c4

File tree

7 files changed

+384
-24
lines changed

7 files changed

+384
-24
lines changed

common/src/main/java/dev/cel/common/CelOptions.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ public enum ProtoUnsetFieldOptions {
6767

6868
public abstract boolean retainUnbalancedLogicalExpressions();
6969

70+
public abstract boolean enableHiddenAccumulatorVar();
71+
7072
// Type-Checker related options
7173

7274
public abstract boolean enableCompileTimeOverloadResolution();
@@ -188,6 +190,7 @@ public static Builder newBuilder() {
188190
.populateMacroCalls(false)
189191
.retainRepeatedUnaryOperators(false)
190192
.retainUnbalancedLogicalExpressions(false)
193+
.enableHiddenAccumulatorVar(false)
191194
// Type-Checker options
192195
.enableCompileTimeOverloadResolution(false)
193196
.enableHomogeneousLiterals(false)
@@ -319,6 +322,16 @@ public abstract static class Builder {
319322
*/
320323
public abstract Builder retainUnbalancedLogicalExpressions(boolean value);
321324

325+
/**
326+
* Enable the use of a hidden accumulator variable name.
327+
*
328+
* <p>This is a temporary option to transition to using an internal identifier for the
329+
* accumulator variable used by builtin comprehension macros. When enabled, parses result in a
330+
* semantically equivalent AST, but with a different accumulator variable that can't be directly
331+
* referenced in the source expression.
332+
*/
333+
public abstract Builder enableHiddenAccumulatorVar(boolean value);
334+
322335
// Type-Checker related options
323336

324337
/**

parser/src/main/java/dev/cel/parser/CelMacroExprFactory.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ public final CelExpr reportError(String message) {
5151
/** Reports a {@link CelIssue} and returns a sentinel {@link CelExpr} that indicates an error. */
5252
public abstract CelExpr reportError(CelIssue error);
5353

54+
/** Returns the default accumulator variable name used by macros implementing comprehensions. */
55+
public abstract String getAccumulatorVarName();
56+
5457
/** Retrieves the source location for the given {@link CelExpr} ID. */
5558
public final CelSourceLocation getSourceLocation(CelExpr expr) {
5659
return getSourceLocation(expr.id());

parser/src/main/java/dev/cel/parser/CelStandardMacro.java

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,6 @@ public enum CelStandardMacro {
7878
public static final ImmutableSet<CelStandardMacro> STANDARD_MACROS =
7979
ImmutableSet.of(HAS, ALL, EXISTS, EXISTS_ONE, MAP, MAP_FILTER, FILTER);
8080

81-
private static final String ACCUMULATOR_VAR = "__result__";
82-
8381
private final CelMacro macro;
8482

8583
CelStandardMacro(CelMacro macro) {
@@ -123,14 +121,23 @@ private static Optional<CelExpr> expandAllMacro(
123121
CelExpr accuInit = exprFactory.newBoolLiteral(true);
124122
CelExpr condition =
125123
exprFactory.newGlobalCall(
126-
Operator.NOT_STRICTLY_FALSE.getFunction(), exprFactory.newIdentifier(ACCUMULATOR_VAR));
124+
Operator.NOT_STRICTLY_FALSE.getFunction(),
125+
exprFactory.newIdentifier(exprFactory.getAccumulatorVarName()));
127126
CelExpr step =
128127
exprFactory.newGlobalCall(
129-
Operator.LOGICAL_AND.getFunction(), exprFactory.newIdentifier(ACCUMULATOR_VAR), arg1);
130-
CelExpr result = exprFactory.newIdentifier(ACCUMULATOR_VAR);
128+
Operator.LOGICAL_AND.getFunction(),
129+
exprFactory.newIdentifier(exprFactory.getAccumulatorVarName()),
130+
arg1);
131+
CelExpr result = exprFactory.newIdentifier(exprFactory.getAccumulatorVarName());
131132
return Optional.of(
132133
exprFactory.fold(
133-
arg0.ident().name(), target, ACCUMULATOR_VAR, accuInit, condition, step, result));
134+
arg0.ident().name(),
135+
target,
136+
exprFactory.getAccumulatorVarName(),
137+
accuInit,
138+
condition,
139+
step,
140+
result));
134141
}
135142

136143
// CelMacroExpander implementation for CEL's exists() macro.
@@ -149,14 +156,23 @@ private static Optional<CelExpr> expandExistsMacro(
149156
exprFactory.newGlobalCall(
150157
Operator.NOT_STRICTLY_FALSE.getFunction(),
151158
exprFactory.newGlobalCall(
152-
Operator.LOGICAL_NOT.getFunction(), exprFactory.newIdentifier(ACCUMULATOR_VAR)));
159+
Operator.LOGICAL_NOT.getFunction(),
160+
exprFactory.newIdentifier(exprFactory.getAccumulatorVarName())));
153161
CelExpr step =
154162
exprFactory.newGlobalCall(
155-
Operator.LOGICAL_OR.getFunction(), exprFactory.newIdentifier(ACCUMULATOR_VAR), arg1);
156-
CelExpr result = exprFactory.newIdentifier(ACCUMULATOR_VAR);
163+
Operator.LOGICAL_OR.getFunction(),
164+
exprFactory.newIdentifier(exprFactory.getAccumulatorVarName()),
165+
arg1);
166+
CelExpr result = exprFactory.newIdentifier(exprFactory.getAccumulatorVarName());
157167
return Optional.of(
158168
exprFactory.fold(
159-
arg0.ident().name(), target, ACCUMULATOR_VAR, accuInit, condition, step, result));
169+
arg0.ident().name(),
170+
target,
171+
exprFactory.getAccumulatorVarName(),
172+
accuInit,
173+
condition,
174+
step,
175+
result));
160176
}
161177

162178
// CelMacroExpander implementation for CEL's exists_one() macro.
@@ -178,17 +194,23 @@ private static Optional<CelExpr> expandExistsOneMacro(
178194
arg1,
179195
exprFactory.newGlobalCall(
180196
Operator.ADD.getFunction(),
181-
exprFactory.newIdentifier(ACCUMULATOR_VAR),
197+
exprFactory.newIdentifier(exprFactory.getAccumulatorVarName()),
182198
exprFactory.newIntLiteral(1)),
183-
exprFactory.newIdentifier(ACCUMULATOR_VAR));
199+
exprFactory.newIdentifier(exprFactory.getAccumulatorVarName()));
184200
CelExpr result =
185201
exprFactory.newGlobalCall(
186202
Operator.EQUALS.getFunction(),
187-
exprFactory.newIdentifier(ACCUMULATOR_VAR),
203+
exprFactory.newIdentifier(exprFactory.getAccumulatorVarName()),
188204
exprFactory.newIntLiteral(1));
189205
return Optional.of(
190206
exprFactory.fold(
191-
arg0.ident().name(), target, ACCUMULATOR_VAR, accuInit, condition, step, result));
207+
arg0.ident().name(),
208+
target,
209+
exprFactory.getAccumulatorVarName(),
210+
accuInit,
211+
condition,
212+
step,
213+
result));
192214
}
193215

194216
// CelMacroExpander implementation for CEL's map() macro.
@@ -218,25 +240,25 @@ private static Optional<CelExpr> expandMapMacro(
218240
CelExpr step =
219241
exprFactory.newGlobalCall(
220242
Operator.ADD.getFunction(),
221-
exprFactory.newIdentifier(ACCUMULATOR_VAR),
243+
exprFactory.newIdentifier(exprFactory.getAccumulatorVarName()),
222244
exprFactory.newList(arg1));
223245
if (arg2 != null) {
224246
step =
225247
exprFactory.newGlobalCall(
226248
Operator.CONDITIONAL.getFunction(),
227249
arg2,
228250
step,
229-
exprFactory.newIdentifier(ACCUMULATOR_VAR));
251+
exprFactory.newIdentifier(exprFactory.getAccumulatorVarName()));
230252
}
231253
return Optional.of(
232254
exprFactory.fold(
233255
arg0.ident().name(),
234256
target,
235-
ACCUMULATOR_VAR,
257+
exprFactory.getAccumulatorVarName(),
236258
accuInit,
237259
condition,
238260
step,
239-
exprFactory.newIdentifier(ACCUMULATOR_VAR)));
261+
exprFactory.newIdentifier(exprFactory.getAccumulatorVarName())));
240262
}
241263

242264
// CelMacroExpander implementation for CEL's filter() macro.
@@ -255,23 +277,23 @@ private static Optional<CelExpr> expandFilterMacro(
255277
CelExpr step =
256278
exprFactory.newGlobalCall(
257279
Operator.ADD.getFunction(),
258-
exprFactory.newIdentifier(ACCUMULATOR_VAR),
280+
exprFactory.newIdentifier(exprFactory.getAccumulatorVarName()),
259281
exprFactory.newList(arg0));
260282
step =
261283
exprFactory.newGlobalCall(
262284
Operator.CONDITIONAL.getFunction(),
263285
arg1,
264286
step,
265-
exprFactory.newIdentifier(ACCUMULATOR_VAR));
287+
exprFactory.newIdentifier(exprFactory.getAccumulatorVarName()));
266288
return Optional.of(
267289
exprFactory.fold(
268290
arg0.ident().name(),
269291
target,
270-
ACCUMULATOR_VAR,
292+
exprFactory.getAccumulatorVarName(),
271293
accuInit,
272294
condition,
273295
step,
274-
exprFactory.newIdentifier(ACCUMULATOR_VAR)));
296+
exprFactory.newIdentifier(exprFactory.getAccumulatorVarName())));
275297
}
276298

277299
private static CelExpr reportArgumentError(CelMacroExprFactory exprFactory, CelExpr argument) {

parser/src/main/java/dev/cel/parser/Parser.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ final class Parser extends CELBaseVisitor<CelExpr> {
125125
"var",
126126
"void",
127127
"while");
128+
private static final String ACCUMULATOR_NAME = "__result__";
129+
private static final String HIDDEN_ACCUMULATOR_NAME = "@result";
128130

129131
static CelValidationResult parse(CelParserImpl parser, CelSource source, CelOptions options) {
130132
if (source.getContent().size() > options.maxExpressionCodePointSize()) {
@@ -142,7 +144,11 @@ static CelValidationResult parse(CelParserImpl parser, CelSource source, CelOpti
142144
CELParser antlrParser = new CELParser(new CommonTokenStream(antlrLexer));
143145
CelSource.Builder sourceInfo = source.toBuilder();
144146
sourceInfo.setDescription(source.getDescription());
145-
ExprFactory exprFactory = new ExprFactory(antlrParser, sourceInfo);
147+
ExprFactory exprFactory =
148+
new ExprFactory(
149+
antlrParser,
150+
sourceInfo,
151+
options.enableHiddenAccumulatorVar() ? HIDDEN_ACCUMULATOR_NAME : ACCUMULATOR_NAME);
146152
Parser parserImpl = new Parser(parser, options, sourceInfo, exprFactory);
147153
ErrorListener errorListener = new ErrorListener(exprFactory);
148154
antlrLexer.removeErrorListeners();
@@ -1033,12 +1039,17 @@ private static final class ExprFactory extends CelMacroExprFactory {
10331039
private final CelSource.Builder sourceInfo;
10341040
private final ArrayList<CelIssue> issues;
10351041
private final ArrayDeque<Integer> positions;
1042+
private final String accumulatorVarName;
10361043

1037-
private ExprFactory(org.antlr.v4.runtime.Parser recognizer, CelSource.Builder sourceInfo) {
1044+
private ExprFactory(
1045+
org.antlr.v4.runtime.Parser recognizer,
1046+
CelSource.Builder sourceInfo,
1047+
String accumulatorVarName) {
10381048
this.recognizer = recognizer;
10391049
this.sourceInfo = sourceInfo;
10401050
this.issues = new ArrayList<>();
10411051
this.positions = new ArrayDeque<>(1); // Currently this usually contains at most 1 position.
1052+
this.accumulatorVarName = accumulatorVarName;
10421053
}
10431054

10441055
// Implementation of CelExprFactory.
@@ -1062,6 +1073,11 @@ public CelExpr reportError(CelIssue error) {
10621073
return ERROR;
10631074
}
10641075

1076+
@Override
1077+
public String getAccumulatorVarName() {
1078+
return accumulatorVarName;
1079+
}
1080+
10651081
// Internal methods used by the parser but not part of the public API.
10661082
@FormatMethod
10671083
@CanIgnoreReturnValue

parser/src/test/java/dev/cel/parser/CelMacroExprFactoryTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ public CelExpr reportError(CelIssue issue) {
6161
return CelExpr.newBuilder().setId(nextExprId()).setConstant(Constants.ERROR).build();
6262
}
6363

64+
@Override
65+
public String getAccumulatorVarName() {
66+
return "__result__";
67+
}
68+
6469
@Override
6570
protected CelSourceLocation getSourceLocation(long exprId) {
6671
return CelSourceLocation.NONE;

parser/src/test/java/dev/cel/parser/CelParserParameterizedTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,16 @@ public final class CelParserParameterizedTest extends BaselineTestCase {
7272
.setOptions(CelOptions.current().populateMacroCalls(true).build())
7373
.build();
7474

75+
private static final CelParser PARSER_WITH_UPDATED_ACCU_VAR =
76+
PARSER
77+
.toParserBuilder()
78+
.setOptions(
79+
CelOptions.current()
80+
.populateMacroCalls(true)
81+
.enableHiddenAccumulatorVar(true)
82+
.build())
83+
.build();
84+
7585
@Test
7686
public void parser() {
7787
runTest(PARSER, "x * 2");
@@ -193,6 +203,17 @@ public void parser() {
193203
"while");
194204
}
195205

206+
@Test
207+
public void parser_updatedAccuVar() {
208+
runTest(PARSER_WITH_UPDATED_ACCU_VAR, "x * 2");
209+
runTest(PARSER_WITH_UPDATED_ACCU_VAR, "has(m.f)");
210+
runTest(PARSER_WITH_UPDATED_ACCU_VAR, "m.exists_one(v, f)");
211+
runTest(PARSER_WITH_UPDATED_ACCU_VAR, "m.all(v, f)");
212+
runTest(PARSER_WITH_UPDATED_ACCU_VAR, "m.map(v, f)");
213+
runTest(PARSER_WITH_UPDATED_ACCU_VAR, "m.map(v, p, f)");
214+
runTest(PARSER_WITH_UPDATED_ACCU_VAR, "m.filter(v, p)");
215+
}
216+
196217
@Test
197218
public void parser_errors() {
198219
runTest(PARSER, "*@a | b");

0 commit comments

Comments
 (0)