1919import static com .google .common .collect .ImmutableList .toImmutableList ;
2020
2121import com .google .auto .value .AutoValue ;
22+ import com .google .common .annotations .VisibleForTesting ;
2223import com .google .common .collect .ImmutableList ;
24+ import com .google .common .collect .ImmutableMap ;
2325import com .google .common .collect .ImmutableSet ;
2426import com .google .errorprone .annotations .CanIgnoreReturnValue ;
2527import com .google .errorprone .annotations .CheckReturnValue ;
3537import dev .cel .common .types .OptionalType ;
3638import dev .cel .common .types .SimpleType ;
3739import dev .cel .common .types .TypeParamType ;
40+ import dev .cel .compiler .CelCompiler ;
41+ import dev .cel .compiler .CelCompilerBuilder ;
3842import dev .cel .extensions .CelExtensions ;
3943import dev .cel .extensions .CelOptionalLibrary ;
44+ import dev .cel .runtime .CelRuntimeBuilder ;
4045import java .util .Arrays ;
4146import java .util .Optional ;
4247
4752@ AutoValue
4853public abstract class CelEnvironment {
4954
55+ @ VisibleForTesting
56+ static final ImmutableMap <String , CanonicalCelExtension > CEL_EXTENSION_CONFIG_MAP =
57+ ImmutableMap .of (
58+ "bindings" , CanonicalCelExtension .BINDINGS ,
59+ "encoders" , CanonicalCelExtension .ENCODERS ,
60+ "lists" , CanonicalCelExtension .LISTS ,
61+ "math" , CanonicalCelExtension .MATH ,
62+ "optional" , CanonicalCelExtension .OPTIONAL ,
63+ "protos" , CanonicalCelExtension .PROTOS ,
64+ "sets" , CanonicalCelExtension .SETS ,
65+ "strings" , CanonicalCelExtension .STRINGS );
66+
5067 /** Environment source in textual format (ex: textproto, YAML). */
5168 public abstract Optional <Source > source ();
5269
@@ -126,12 +143,14 @@ public static Builder newBuilder() {
126143 .setFunctions (ImmutableSet .of ());
127144 }
128145
129- /** Extends the provided {@code cel} environment with this configuration. */
130- public Cel extend (Cel cel , CelOptions celOptions ) throws CelEnvironmentException {
146+ /** Extends the provided {@link CelCompiler} environment with this configuration. */
147+ public CelCompiler extend (CelCompiler celCompiler , CelOptions celOptions )
148+ throws CelEnvironmentException {
131149 try {
132- CelTypeProvider celTypeProvider = cel .getTypeProvider ();
133- CelBuilder celBuilder =
134- cel .toCelBuilder ()
150+ CelTypeProvider celTypeProvider = celCompiler .getTypeProvider ();
151+ CelCompilerBuilder compilerBuilder =
152+ celCompiler
153+ .toCompilerBuilder ()
135154 .setTypeProvider (celTypeProvider )
136155 .setContainer (container ())
137156 .addVarDeclarations (
@@ -144,53 +163,58 @@ public Cel extend(Cel cel, CelOptions celOptions) throws CelEnvironmentException
144163 .collect (toImmutableList ()));
145164
146165 if (!container ().isEmpty ()) {
147- celBuilder .setContainer (container ());
166+ compilerBuilder .setContainer (container ());
148167 }
149168
150- addAllExtensions (celBuilder , celOptions );
169+ addAllCompilerExtensions (compilerBuilder , celOptions );
170+
171+ return compilerBuilder .build ();
172+ } catch (RuntimeException e ) {
173+ throw new CelEnvironmentException (e .getMessage (), e );
174+ }
175+ }
176+
177+ /** Extends the provided {@link Cel} environment with this configuration. */
178+ public Cel extend (Cel cel , CelOptions celOptions ) throws CelEnvironmentException {
179+ try {
180+ // Casting is necessary to only extend the compiler here
181+ CelCompiler celCompiler = extend ((CelCompiler ) cel , celOptions );
182+
183+ CelRuntimeBuilder celRuntimeBuilder = cel .toRuntimeBuilder ();
184+ addAllRuntimeExtensions (celRuntimeBuilder , celOptions );
151185
152- return celBuilder . build ();
186+ return CelFactory . combine ( celCompiler , celRuntimeBuilder . build () );
153187 } catch (RuntimeException e ) {
154188 throw new CelEnvironmentException (e .getMessage (), e );
155189 }
156190 }
157191
158- private void addAllExtensions (CelBuilder celBuilder , CelOptions celOptions ) {
192+ private void addAllCompilerExtensions (
193+ CelCompilerBuilder celCompilerBuilder , CelOptions celOptions ) {
159194 // TODO: Add capability to accept user defined exceptions
160195 for (ExtensionConfig extensionConfig : extensions ()) {
161- switch (extensionConfig .name ()) {
162- case "bindings" :
163- celBuilder .addCompilerLibraries (CelExtensions .bindings ());
164- break ;
165- case "encoders" :
166- celBuilder .addCompilerLibraries (CelExtensions .encoders ());
167- celBuilder .addRuntimeLibraries (CelExtensions .encoders ());
168- break ;
169- case "math" :
170- celBuilder .addCompilerLibraries (CelExtensions .math (celOptions ));
171- celBuilder .addRuntimeLibraries (CelExtensions .math (celOptions ));
172- break ;
173- case "optional" :
174- celBuilder .addCompilerLibraries (CelOptionalLibrary .INSTANCE );
175- celBuilder .addRuntimeLibraries (CelOptionalLibrary .INSTANCE );
176- break ;
177- case "protos" :
178- celBuilder .addCompilerLibraries (CelExtensions .protos ());
179- break ;
180- case "strings" :
181- celBuilder .addCompilerLibraries (CelExtensions .strings ());
182- celBuilder .addRuntimeLibraries (CelExtensions .strings ());
183- break ;
184- case "sets" :
185- celBuilder .addCompilerLibraries (CelExtensions .sets (celOptions ));
186- celBuilder .addRuntimeLibraries (CelExtensions .sets (celOptions ));
187- break ;
188- default :
189- throw new IllegalArgumentException ("Unrecognized extension: " + extensionConfig .name ());
190- }
196+ CanonicalCelExtension extension = getExtensionOrThrow (extensionConfig .name ());
197+ extension .addCompilerExtension (celCompilerBuilder , celOptions );
198+ }
199+ }
200+
201+ private void addAllRuntimeExtensions (CelRuntimeBuilder celRuntimeBuilder , CelOptions celOptions ) {
202+ // TODO: Add capability to accept user defined exceptions
203+ for (ExtensionConfig extensionConfig : extensions ()) {
204+ CanonicalCelExtension extension = getExtensionOrThrow (extensionConfig .name ());
205+ extension .addRuntimeExtension (celRuntimeBuilder , celOptions );
191206 }
192207 }
193208
209+ private static CanonicalCelExtension getExtensionOrThrow (String extensionName ) {
210+ CanonicalCelExtension extension = CEL_EXTENSION_CONFIG_MAP .get (extensionName );
211+ if (extension == null ) {
212+ throw new IllegalArgumentException ("Unrecognized extension: " + extensionName );
213+ }
214+
215+ return extension ;
216+ }
217+
194218 /** Represents a policy variable declaration. */
195219 @ AutoValue
196220 public abstract static class VariableDecl {
@@ -529,4 +553,63 @@ public static ExtensionConfig of(String name, int version) {
529553 return newBuilder ().setName (name ).setVersion (version ).build ();
530554 }
531555 }
556+
557+ @ VisibleForTesting
558+ enum CanonicalCelExtension {
559+ BINDINGS ((compilerBuilder , options ) -> compilerBuilder .addLibraries (CelExtensions .bindings ())),
560+ PROTOS ((compilerBuilder , options ) -> compilerBuilder .addLibraries (CelExtensions .protos ())),
561+ ENCODERS (
562+ (compilerBuilder , options ) -> compilerBuilder .addLibraries (CelExtensions .encoders ()),
563+ (runtimeBuilder , options ) -> runtimeBuilder .addLibraries (CelExtensions .encoders ())),
564+ MATH (
565+ (compilerBuilder , options ) -> compilerBuilder .addLibraries (CelExtensions .math (options )),
566+ (runtimeBuilder , options ) -> runtimeBuilder .addLibraries (CelExtensions .math (options ))),
567+ OPTIONAL (
568+ (compilerBuilder , options ) -> compilerBuilder .addLibraries (CelOptionalLibrary .INSTANCE ),
569+ (runtimeBuilder , options ) -> runtimeBuilder .addLibraries (CelOptionalLibrary .INSTANCE )),
570+ STRINGS (
571+ (compilerBuilder , options ) -> compilerBuilder .addLibraries (CelExtensions .strings ()),
572+ (runtimeBuilder , options ) -> runtimeBuilder .addLibraries (CelExtensions .strings ())),
573+ SETS (
574+ (compilerBuilder , options ) -> compilerBuilder .addLibraries (CelExtensions .sets (options )),
575+ (runtimeBuilder , options ) -> runtimeBuilder .addLibraries (CelExtensions .sets (options ))),
576+ LISTS (
577+ (compilerBuilder , options ) -> compilerBuilder .addLibraries (CelExtensions .lists ()),
578+ (runtimeBuilder , options ) -> runtimeBuilder .addLibraries (CelExtensions .lists ()));
579+
580+ @ SuppressWarnings ("ImmutableEnumChecker" )
581+ private final CompilerExtensionApplier compilerExtensionApplier ;
582+
583+ @ SuppressWarnings ("ImmutableEnumChecker" )
584+ private final RuntimeExtensionApplier runtimeExtensionApplier ;
585+
586+ interface CompilerExtensionApplier {
587+ void apply (CelCompilerBuilder compilerBuilder , CelOptions options );
588+ }
589+
590+ interface RuntimeExtensionApplier {
591+ void apply (CelRuntimeBuilder runtimeBuilder , CelOptions options );
592+ }
593+
594+ void addCompilerExtension (CelCompilerBuilder compilerBuilder , CelOptions options ) {
595+ compilerExtensionApplier .apply (compilerBuilder , options );
596+ }
597+
598+ void addRuntimeExtension (CelRuntimeBuilder runtimeBuilder , CelOptions options ) {
599+ runtimeExtensionApplier .apply (runtimeBuilder , options );
600+ }
601+
602+ CanonicalCelExtension (CompilerExtensionApplier compilerExtensionApplier ) {
603+ this (
604+ compilerExtensionApplier ,
605+ (runtimeBuilder , options ) -> {}); // no-op. Not all extensions augment the runtime.
606+ }
607+
608+ CanonicalCelExtension (
609+ CompilerExtensionApplier compilerExtensionApplier ,
610+ RuntimeExtensionApplier runtimeExtensionApplier ) {
611+ this .compilerExtensionApplier = compilerExtensionApplier ;
612+ this .runtimeExtensionApplier = runtimeExtensionApplier ;
613+ }
614+ }
532615}
0 commit comments