Skip to content

Commit 8fd2908

Browse files
dmitriplotnikovcopybara-github
authored andcommitted
Add support for macro inclusion/exclusion to CelEnvironmentExporter
PiperOrigin-RevId: 785497910
1 parent 94160c0 commit 8fd2908

File tree

13 files changed

+145
-62
lines changed

13 files changed

+145
-62
lines changed

bundle/src/main/java/dev/cel/bundle/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ java_library(
131131
"//common/types:type_providers",
132132
"//extensions",
133133
"//extensions:extension_library",
134+
"//parser:macro",
134135
"@cel_spec//proto/cel/expr:checked_java_proto",
135136
"@maven//:com_google_errorprone_error_prone_annotations",
136137
"@maven//:com_google_guava_guava",

bundle/src/main/java/dev/cel/bundle/CelEnvironment.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -275,12 +275,12 @@ private void applyStandardLibrarySubset(CelCompilerBuilder compilerBuilder) {
275275
} else if (!librarySubset.includedMacros().isEmpty()) {
276276
compilerBuilder.setStandardMacros(
277277
librarySubset.includedMacros().stream()
278-
.map(CelEnvironment::getStandardMacroOrThrow)
278+
.flatMap(name -> getStandardMacrosOrThrow(name).stream())
279279
.collect(toImmutableSet()));
280280
} else if (!librarySubset.excludedMacros().isEmpty()) {
281281
ImmutableSet<CelStandardMacro> set =
282282
librarySubset.excludedMacros().stream()
283-
.map(CelEnvironment::getStandardMacroOrThrow)
283+
.flatMap(name -> getStandardMacrosOrThrow(name).stream())
284284
.collect(toImmutableSet());
285285
compilerBuilder.setStandardMacros(
286286
CelStandardMacro.STANDARD_MACROS.stream()
@@ -311,13 +311,18 @@ private void applyStandardLibrarySubset(CelCompilerBuilder compilerBuilder) {
311311
}
312312
}
313313

314-
private static CelStandardMacro getStandardMacroOrThrow(String macroName) {
314+
private static ImmutableSet<CelStandardMacro> getStandardMacrosOrThrow(String macroName) {
315+
ImmutableSet.Builder<CelStandardMacro> builder = ImmutableSet.builder();
315316
for (CelStandardMacro macro : CelStandardMacro.STANDARD_MACROS) {
316317
if (macro.getFunction().equals(macroName)) {
317-
return macro;
318+
builder.add(macro);
318319
}
319320
}
320-
throw new IllegalArgumentException("unrecognized standard macro `" + macroName + "'");
321+
ImmutableSet<CelStandardMacro> macros = builder.build();
322+
if (macros.isEmpty()) {
323+
throw new IllegalArgumentException("unrecognized standard macro `" + macroName + "'");
324+
}
325+
return macros;
321326
}
322327

323328
private static CanonicalCelExtension getExtensionOrThrow(String extensionName) {

bundle/src/main/java/dev/cel/bundle/CelEnvironmentExporter.java

Lines changed: 65 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,19 @@
3838
import dev.cel.common.CelOverloadDecl;
3939
import dev.cel.common.CelVarDecl;
4040
import dev.cel.common.internal.EnvVisitable;
41+
import dev.cel.common.internal.EnvVisitor;
4142
import dev.cel.common.types.CelProtoTypes;
4243
import dev.cel.common.types.CelType;
4344
import dev.cel.common.types.CelTypes;
4445
import dev.cel.extensions.CelExtensionLibrary;
4546
import dev.cel.extensions.CelExtensions;
47+
import dev.cel.parser.CelMacro;
48+
import dev.cel.parser.CelStandardMacro;
4649
import java.util.ArrayList;
4750
import java.util.Comparator;
4851
import java.util.HashMap;
4952
import java.util.HashSet;
53+
import java.util.List;
5054
import java.util.Map;
5155
import java.util.Set;
5256

@@ -71,14 +75,14 @@
7175
public abstract class CelEnvironmentExporter {
7276

7377
/**
74-
* Maximum number of excluded standard functions before switching to a format that enumerates all
75-
* included functions. The default is 5.
78+
* Maximum number of excluded standard functions and macros before switching to a format that
79+
* enumerates all included functions and macros. The default is 5.
7680
*
7781
* <p>This setting is primarily for stylistic preferences and the intended use of the resulting
7882
* YAML file.
7983
*
80-
* <p>For example, if you want almost all of the standard library with only a few exceptions
81-
* (e.g., to ban a specific function), you would favor an exclusion-based approach by setting an
84+
* <p>For example, if you want almost all the standard library with only a few exceptions (e.g.,
85+
* to ban a specific function), you would favor an exclusion-based approach by setting an
8286
* appropriate threshold.
8387
*
8488
* <p>If you want full control over what is available to the CEL runtime, where no function is
@@ -106,11 +110,11 @@ public abstract static class Builder {
106110
abstract ImmutableSet.Builder<CelExtensionLibrary> extensionLibrariesBuilder();
107111

108112
@CanIgnoreReturnValue
109-
public Builder addStandardExtensions(CelOptions options) {
113+
public Builder addStandardExtensions() {
110114
addExtensionLibraries(
111-
CelExtensions.math(options, 0),
112-
CelExtensions.math(options, 1),
113-
CelExtensions.math(options, 2));
115+
CelExtensions.math(CelOptions.current().build(), 0),
116+
CelExtensions.math(CelOptions.current().build(), 1),
117+
CelExtensions.math(CelOptions.current().build(), 2));
114118
return this;
115119
}
116120

@@ -174,21 +178,30 @@ public CelEnvironment export(Cel cel) {
174178
private void collectInventory(Set<Object> inventory, Cel cel) {
175179
((EnvVisitable) cel)
176180
.accept(
177-
(name, decls) -> {
178-
for (Decl decl : decls) {
179-
if (decl.hasFunction()) {
180-
FunctionDecl function = decl.getFunction();
181-
for (Overload overload : function.getOverloadsList()) {
181+
new EnvVisitor() {
182+
@Override
183+
public void visitDecl(String name, List<Decl> decls) {
184+
for (Decl decl : decls) {
185+
if (decl.hasFunction()) {
186+
FunctionDecl function = decl.getFunction();
187+
for (Overload overload : function.getOverloadsList()) {
188+
inventory.add(
189+
NamedOverload.create(
190+
decl.getName(), CelOverloadDecl.overloadToCelOverload(overload)));
191+
}
192+
} else if (decl.hasIdent()) {
182193
inventory.add(
183-
NamedOverload.create(
184-
decl.getName(), CelOverloadDecl.overloadToCelOverload(overload)));
194+
CelVarDecl.newVarDeclaration(
195+
decl.getName(),
196+
CelProtoTypes.typeToCelType(decl.getIdent().getType())));
185197
}
186-
} else if (decl.hasIdent()) {
187-
inventory.add(
188-
CelVarDecl.newVarDeclaration(
189-
decl.getName(), CelProtoTypes.typeToCelType(decl.getIdent().getType())));
190198
}
191199
}
200+
201+
@Override
202+
public void visitMacro(CelMacro macro) {
203+
inventory.add(macro);
204+
}
192205
});
193206
}
194207

@@ -224,20 +237,28 @@ private void addExtensionConfigsAndRemoveFromInventory(
224237
private boolean checkIfExtensionIsIncludedAndRemoveFromInventory(
225238
Set<Object> inventory, CelExtensionLibrary library) {
226239
ImmutableSet<CelFunctionDecl> functions = library.getFunctions();
227-
ArrayList<Object> itemList = new ArrayList<>(functions.size());
240+
ArrayList<Object> includedItems = new ArrayList<>(functions.size());
228241
for (CelFunctionDecl function : functions) {
229242
for (CelOverloadDecl overload : function.overloads()) {
230243
NamedOverload item = NamedOverload.create(function.name(), overload);
231244
if (!inventory.contains(item)) {
232245
return false;
233246
}
234-
itemList.add(item);
247+
includedItems.add(item);
248+
}
249+
}
250+
251+
ImmutableSet<CelMacro> macros = library.getMacros();
252+
for (CelMacro macro : macros) {
253+
if (!inventory.contains(macro)) {
254+
return false;
235255
}
256+
includedItems.add(macro);
236257
}
237258

238-
// TODO - Add checks for variables and macros.
259+
// TODO - Add checks for variables.
239260

240-
inventory.removeAll(itemList);
261+
inventory.removeAll(includedItems);
241262
return true;
242263
}
243264

@@ -279,18 +300,31 @@ private void addStandardLibrarySubsetAndRemoveFromInventory(
279300
}
280301
});
281302

303+
Set<String> excludedMacros = new HashSet<>();
304+
Set<String> includedMacros = new HashSet<>();
305+
stream(CelStandardMacro.values())
306+
.map(celStandardMacro -> celStandardMacro.getDefinition())
307+
.forEach(
308+
macro -> {
309+
if (inventory.remove(macro)) {
310+
includedMacros.add(macro.getFunction());
311+
} else {
312+
excludedMacros.add(macro.getFunction());
313+
}
314+
});
315+
282316
LibrarySubset.Builder subsetBuilder = LibrarySubset.newBuilder().setDisabled(false);
283-
if (excludedFunctions.size() <= maxExcludedStandardFunctions()
317+
if (excludedFunctions.size() + excludedMacros.size() <= maxExcludedStandardFunctions()
284318
&& excludedOverloads.size() <= maxExcludedStandardFunctionOverloads()) {
285-
subsetBuilder.setExcludedFunctions(
286-
buildFunctionSelectors(excludedFunctions, excludedOverloads));
319+
subsetBuilder
320+
.setExcludedFunctions(buildFunctionSelectors(excludedFunctions, excludedOverloads))
321+
.setExcludedMacros(ImmutableSet.copyOf(excludedMacros));
287322
} else {
288-
subsetBuilder.setIncludedFunctions(
289-
buildFunctionSelectors(includedFunctions, includedOverloads));
323+
subsetBuilder
324+
.setIncludedFunctions(buildFunctionSelectors(includedFunctions, includedOverloads))
325+
.setIncludedMacros(ImmutableSet.copyOf(includedMacros));
290326
}
291327

292-
// TODO - Add support for including/excluding macros.
293-
294328
envBuilder.setStandardLibrarySubset(subsetBuilder.build());
295329
}
296330

@@ -388,3 +422,4 @@ static NamedOverload create(String functionName, CelOverloadDecl overload) {
388422
}
389423
}
390424
}
425+

bundle/src/test/java/dev/cel/bundle/CelEnvironmentExporterTest.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public void extensions_latest() {
5858
.build();
5959

6060
CelEnvironment celEnvironment =
61-
CelEnvironmentExporter.newBuilder().addStandardExtensions(CEL_OPTIONS).build().export(cel);
61+
CelEnvironmentExporter.newBuilder().addStandardExtensions().build().export(cel);
6262

6363
assertThat(celEnvironment.extensions())
6464
.containsExactly(ExtensionConfig.newBuilder().setName("math").setVersion(2).build());
@@ -72,7 +72,7 @@ public void extensions_earlierVersion() {
7272
.build();
7373

7474
CelEnvironment celEnvironment =
75-
CelEnvironmentExporter.newBuilder().addStandardExtensions(CEL_OPTIONS).build().export(cel);
75+
CelEnvironmentExporter.newBuilder().addStandardExtensions().build().export(cel);
7676

7777
assertThat(celEnvironment.extensions())
7878
.containsExactly(ExtensionConfig.newBuilder().setName("math").setVersion(1).build());
@@ -109,6 +109,7 @@ public void standardLibrarySubset_favorExclusion() throws Exception {
109109
FunctionSelector.create("matches", ImmutableSet.of()),
110110
FunctionSelector.create(
111111
"timestamp", ImmutableSet.of("string_to_timestamp"))))
112+
.setExcludedMacros(ImmutableSet.of("map", "filter"))
112113
.build());
113114
}
114115

@@ -151,6 +152,8 @@ public void standardLibrarySubset_favorInclusion() throws Exception {
151152
.collect(toCollection(HashSet::new));
152153
assertThat(additionOverloads).containsNoneOf("add_bytes", "add_list", "add_string");
153154

155+
assertThat(actual.includedMacros()).containsNoneOf("map", "filter");
156+
154157
// Random-check a few standard overloads
155158
assertThat(additionOverloads).containsAtLeast("add_int64", "add_uint64", "add_double");
156159

@@ -159,6 +162,7 @@ public void standardLibrarySubset_favorInclusion() throws Exception {
159162
.contains(FunctionSelector.create("-_", ImmutableSet.of()));
160163
assertThat(actual.includedFunctions())
161164
.contains(FunctionSelector.create("getDayOfYear", ImmutableSet.of()));
165+
assertThat(actual.includedMacros()).containsAtLeast("all", "exists", "exists_one", "has");
162166
}
163167

164168
@Test
@@ -181,7 +185,7 @@ public void customFunctions() {
181185
.build();
182186

183187
CelEnvironmentExporter exporter =
184-
CelEnvironmentExporter.newBuilder().addStandardExtensions(CEL_OPTIONS).build();
188+
CelEnvironmentExporter.newBuilder().addStandardExtensions().build();
185189
CelEnvironment celEnvironment = exporter.export(cel);
186190

187191
assertThat(celEnvironment.functions())
@@ -220,7 +224,7 @@ public void customVariables() {
220224
.build();
221225

222226
CelEnvironmentExporter exporter =
223-
CelEnvironmentExporter.newBuilder().addStandardExtensions(CEL_OPTIONS).build();
227+
CelEnvironmentExporter.newBuilder().addStandardExtensions().build();
224228
CelEnvironment celEnvironment = exporter.export(cel);
225229

226230
assertThat(celEnvironment.variables())
@@ -235,3 +239,4 @@ public void customVariables() {
235239
.containsNoneOf("double", "null_type");
236240
}
237241
}
242+

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

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import dev.cel.common.CelProtoAbstractSyntaxTree;
3737
import dev.cel.common.CelVarDecl;
3838
import dev.cel.common.internal.EnvVisitable;
39+
import dev.cel.common.internal.EnvVisitor;
3940
import dev.cel.common.internal.Errors;
4041
import dev.cel.common.types.CelProtoTypes;
4142
import dev.cel.common.types.CelType;
@@ -50,11 +51,13 @@
5051
import dev.cel.common.types.TypeParamType;
5152
import dev.cel.common.types.TypeType;
5253
import dev.cel.expr.conformance.proto3.TestAllTypes;
54+
import dev.cel.parser.CelMacro;
5355
import dev.cel.testing.CelAdorner;
5456
import dev.cel.testing.CelBaselineTestCase;
5557
import dev.cel.testing.CelDebug;
5658
import dev.cel.testing.testdata.proto3.StandaloneGlobalEnum;
5759
import java.util.Arrays;
60+
import java.util.List;
5861
import org.junit.Test;
5962
import org.junit.runner.RunWith;
6063

@@ -106,26 +109,33 @@ public void standardEnvDump() throws Exception {
106109

107110
((EnvVisitable) celCompiler)
108111
.accept(
109-
(name, decls) -> {
110-
// TODO: Remove proto to native type adaptation after changing interface
111-
for (Decl decl : decls) {
112-
if (decl.hasFunction()) {
113-
CelFunctionDecl celFunctionDecl =
114-
CelFunctionDecl.newFunctionDeclaration(
115-
decl.getName(),
116-
decl.getFunction().getOverloadsList().stream()
117-
.map(CelOverloadDecl::overloadToCelOverload)
118-
.collect(toImmutableList()));
119-
testOutput().println(formatFunctionDecl(celFunctionDecl));
120-
} else if (decl.hasIdent()) {
121-
CelVarDecl celVarDecl =
122-
CelVarDecl.newVarDeclaration(
123-
decl.getName(), CelProtoTypes.typeToCelType(decl.getIdent().getType()));
124-
testOutput().println(formatVarDecl(celVarDecl));
125-
} else {
126-
throw new IllegalArgumentException("Invalid declaration: " + decl);
112+
new EnvVisitor() {
113+
@Override
114+
public void visitDecl(String name, List<Decl> decls) {
115+
// TODO: Remove proto to native type adaptation after changing
116+
// interface
117+
for (Decl decl : decls) {
118+
if (decl.hasFunction()) {
119+
CelFunctionDecl celFunctionDecl =
120+
CelFunctionDecl.newFunctionDeclaration(
121+
decl.getName(),
122+
decl.getFunction().getOverloadsList().stream()
123+
.map(CelOverloadDecl::overloadToCelOverload)
124+
.collect(toImmutableList()));
125+
testOutput().println(formatFunctionDecl(celFunctionDecl));
126+
} else if (decl.hasIdent()) {
127+
CelVarDecl celVarDecl =
128+
CelVarDecl.newVarDeclaration(
129+
decl.getName(), CelProtoTypes.typeToCelType(decl.getIdent().getType()));
130+
testOutput().println(formatVarDecl(celVarDecl));
131+
} else {
132+
throw new IllegalArgumentException("Invalid declaration: " + decl);
133+
}
127134
}
128135
}
136+
137+
@Override
138+
public void visitMacro(CelMacro macro) {}
129139
});
130140
}
131141

common/src/main/java/dev/cel/common/internal/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ java_library(
236236
],
237237
deps = [
238238
"//common/annotations",
239+
"//parser:macro",
239240
"@cel_spec//proto/cel/expr:checked_java_proto",
240241
],
241242
)

common/src/main/java/dev/cel/common/internal/EnvVisitor.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@
1616

1717
import dev.cel.expr.Decl;
1818
import dev.cel.common.annotations.Internal;
19+
import dev.cel.parser.CelMacro;
1920
import java.util.List;
2021

2122
/**
2223
* Simple API for visiting the declarations of a CEL environment
2324
*
2425
* <p>CEL Library Internals. Do Not Use.
2526
*/
26-
@FunctionalInterface
2727
@Internal
2828
public interface EnvVisitor {
2929

@@ -32,4 +32,7 @@ public interface EnvVisitor {
3232
* with that name.
3333
*/
3434
void visitDecl(String name, List<Decl> decls);
35+
36+
/** Visit the CEL macro. */
37+
void visitMacro(CelMacro macro);
3538
}

0 commit comments

Comments
 (0)