4848import dev .cel .compiler .CelCompilerLibrary ;
4949import dev .cel .extensions .CelExtensions ;
5050import dev .cel .parser .CelStandardMacro ;
51+ import dev .cel .runtime .CelRuntime ;
5152import dev .cel .runtime .CelRuntimeBuilder ;
5253import dev .cel .runtime .CelRuntimeLibrary ;
5354import java .util .Arrays ;
@@ -108,6 +109,12 @@ public abstract class CelEnvironment {
108109 /** Standard library subset (which macros, functions to include/exclude) */
109110 public abstract Optional <LibrarySubset > standardLibrarySubset ();
110111
112+ /** Feature flags to enable in the environment. */
113+ public abstract ImmutableSet <FeatureFlag > features ();
114+
115+ /** Limits to set in the environment. */
116+ public abstract ImmutableSet <Limit > limits ();
117+
111118 /** Builder for {@link CelEnvironment}. */
112119 @ AutoValue .Builder
113120 public abstract static class Builder {
@@ -159,6 +166,20 @@ public Builder setFunctions(FunctionDecl... functions) {
159166
160167 public abstract Builder setStandardLibrarySubset (LibrarySubset stdLibrarySubset );
161168
169+ @ CanIgnoreReturnValue
170+ public Builder setFeatures (FeatureFlag ... featureFlags ) {
171+ return setFeatures (ImmutableSet .copyOf (featureFlags ));
172+ }
173+
174+ public abstract Builder setFeatures (ImmutableSet <FeatureFlag > featureFlags );
175+
176+ @ CanIgnoreReturnValue
177+ public Builder setLimits (Limit ... limits ) {
178+ return setLimits (ImmutableSet .copyOf (limits ));
179+ }
180+
181+ public abstract Builder setLimits (ImmutableSet <Limit > limits );
182+
162183 abstract CelEnvironment autoBuild ();
163184
164185 @ CheckReturnValue
@@ -188,18 +209,22 @@ public static Builder newBuilder() {
188209 .setDescription ("" )
189210 .setContainer (CelContainer .ofName ("" ))
190211 .setVariables (ImmutableSet .of ())
191- .setFunctions (ImmutableSet .of ());
212+ .setFunctions (ImmutableSet .of ())
213+ .setFeatures (ImmutableSet .of ())
214+ .setLimits (ImmutableSet .of ());
192215 }
193216
194217 /** Extends the provided {@link CelCompiler} environment with this configuration. */
195218 public CelCompiler extend (CelCompiler celCompiler , CelOptions celOptions )
196219 throws CelEnvironmentException {
220+ celOptions = applyEnvironmentOptions (celOptions );
197221 try {
198222 CelTypeProvider celTypeProvider = celCompiler .getTypeProvider ();
199223 CelCompilerBuilder compilerBuilder =
200224 celCompiler
201225 .toCompilerBuilder ()
202226 .setContainer (container ())
227+ .setOptions (celOptions )
203228 .setTypeProvider (celTypeProvider )
204229 .addVarDeclarations (
205230 variables ().stream ()
@@ -222,19 +247,46 @@ public CelCompiler extend(CelCompiler celCompiler, CelOptions celOptions)
222247
223248 /** Extends the provided {@link Cel} environment with this configuration. */
224249 public Cel extend (Cel cel , CelOptions celOptions ) throws CelEnvironmentException {
250+ celOptions = applyEnvironmentOptions (celOptions );
225251 try {
226252 // Casting is necessary to only extend the compiler here
227253 CelCompiler celCompiler = extend ((CelCompiler ) cel , celOptions );
228254
229- CelRuntimeBuilder celRuntimeBuilder = cel .toRuntimeBuilder ();
230- addAllRuntimeExtensions (celRuntimeBuilder , celOptions );
255+ CelRuntime celRuntime = extendRuntime (cel , celOptions );
231256
232- return CelFactory .combine (celCompiler , celRuntimeBuilder . build () );
257+ return CelFactory .combine (celCompiler , celRuntime );
233258 } catch (RuntimeException e ) {
234259 throw new CelEnvironmentException (e .getMessage (), e );
235260 }
236261 }
237262
263+ private CelOptions applyEnvironmentOptions (CelOptions celOptions ) {
264+ CelOptions .Builder optionsBuilder = celOptions .toBuilder ();
265+ for (FeatureFlag featureFlag : features ()) {
266+ if (featureFlag .name ().equals ("cel.feature.macro_call_tracking" )) {
267+ optionsBuilder .populateMacroCalls (featureFlag .enabled ());
268+ } else if (featureFlag .name ().equals ("cel.feature.backtick_escape_syntax" )) {
269+ optionsBuilder .enableQuotedIdentifierSyntax (featureFlag .enabled ());
270+ } else if (featureFlag .name ().equals ("cel.feature.cross_type_numeric_comparisons" )) {
271+ optionsBuilder .enableHeterogeneousNumericComparisons (featureFlag .enabled ());
272+ } else {
273+ throw new IllegalArgumentException ("Unknown feature flag: " + featureFlag .name ());
274+ }
275+ }
276+ for (Limit limit : limits ()) {
277+ if (limit .name ().equals ("cel.limit.expression_code_points" )) {
278+ optionsBuilder .maxExpressionCodePointSize (limit .value ());
279+ } else if (limit .name ().equals ("cel.limit.parse_error_recovery" )) {
280+ optionsBuilder .maxParseErrorRecoveryLimit (limit .value ());
281+ } else if (limit .name ().equals ("cel.limit.parse_recursion_depth" )) {
282+ optionsBuilder .maxParseRecursionDepth (limit .value ());
283+ } else {
284+ throw new IllegalArgumentException ("Unknown limit: " + limit .name ());
285+ }
286+ }
287+ return optionsBuilder .build ();
288+ }
289+
238290 private void addAllCompilerExtensions (
239291 CelCompilerBuilder celCompilerBuilder , CelOptions celOptions ) {
240292 // TODO: Add capability to accept user defined exceptions
@@ -250,7 +302,9 @@ private void addAllCompilerExtensions(
250302 }
251303 }
252304
253- private void addAllRuntimeExtensions (CelRuntimeBuilder celRuntimeBuilder , CelOptions celOptions ) {
305+ private CelRuntime extendRuntime (CelRuntime celRuntime , CelOptions celOptions ) {
306+ CelRuntimeBuilder celRuntimeBuilder = celRuntime .toRuntimeBuilder ();
307+ celRuntimeBuilder .setOptions (celOptions );
254308 // TODO: Add capability to accept user defined exceptions
255309 for (ExtensionConfig extensionConfig : extensions ()) {
256310 CanonicalCelExtension extension = getExtensionOrThrow (extensionConfig .name ());
@@ -262,6 +316,7 @@ private void addAllRuntimeExtensions(CelRuntimeBuilder celRuntimeBuilder, CelOpt
262316 celRuntimeBuilder .addLibraries (celRuntimeLibrary );
263317 }
264318 }
319+ return celRuntimeBuilder .build ();
265320 }
266321
267322 private void applyStandardLibrarySubset (CelCompilerBuilder compilerBuilder ) {
@@ -625,6 +680,39 @@ public CelType toCelType(CelTypeProvider celTypeProvider) {
625680 }
626681 }
627682
683+ /** Represents a feature flag that can be enabled in the environment. */
684+ @ AutoValue
685+ public abstract static class FeatureFlag {
686+ /** Normalized name of the feature flag. */
687+ public abstract String name ();
688+
689+ /** Whether the feature is enabled or disabled. */
690+ public abstract boolean enabled ();
691+
692+ public static FeatureFlag create (String name , boolean enabled ) {
693+ return new AutoValue_CelEnvironment_FeatureFlag (name , enabled );
694+ }
695+ }
696+
697+ /**
698+ * Represents a configurable limit in the environment.
699+ *
700+ * <p>A negative value indicates no limit. If not specified, the limit should be set to the
701+ * library default.
702+ */
703+ @ AutoValue
704+ public abstract static class Limit {
705+ /** Normalized name of the limit (e.g. cel.limit.expression_code_points */
706+ public abstract String name ();
707+
708+ /** The value of the limit, -1 means no limit. */
709+ public abstract int value ();
710+
711+ public static Limit create (String name , int value ) {
712+ return new AutoValue_CelEnvironment_Limit (name , value );
713+ }
714+ }
715+
628716 /**
629717 * Represents a configuration for a canonical CEL extension that can be enabled in the
630718 * environment.
0 commit comments