2525import com .google .common .util .concurrent .ListeningExecutorService ;
2626import com .google .errorprone .annotations .CheckReturnValue ;
2727import com .google .errorprone .annotations .Immutable ;
28+ import com .google .re2j .Pattern ;
2829import dev .cel .common .CelAbstractSyntaxTree ;
2930import dev .cel .common .CelContainer ;
3031import dev .cel .common .CelOptions ;
4344import dev .cel .common .ast .CelExpr .ExprKind .Kind ;
4445import dev .cel .common .ast .CelReference ;
4546import dev .cel .common .exceptions .CelOverloadNotFoundException ;
47+ import dev .cel .common .exceptions .CelRuntimeException ;
4648import dev .cel .common .types .CelKind ;
4749import dev .cel .common .types .CelType ;
4850import dev .cel .common .types .CelTypeProvider ;
5456import dev .cel .runtime .CelAsyncFunctionOverload ;
5557import dev .cel .runtime .CelEvaluationException ;
5658import dev .cel .runtime .CelEvaluationExceptionBuilder ;
59+ import dev .cel .runtime .CelFunctionBinding ;
5760import dev .cel .runtime .CelResolvedOverload ;
5861import dev .cel .runtime .DefaultDispatcher ;
5962import dev .cel .runtime .RuntimeEquality ;
63+ import dev .cel .runtime .RuntimeHelpers ;
6064import java .util .Arrays ;
6165import java .util .HashMap ;
6266import java .util .NoSuchElementException ;
7175@ Internal
7276public final class ProgramPlanner {
7377 private static final String MAP_INSERT_FUNCTION = "cel.@mapInsert" ;
78+ private static final ImmutableList <Class <?>> MATCHES_PARAMETER_TYPES =
79+ ImmutableList .of (String .class , String .class );
7480
7581 private final CelTypeProvider typeProvider ;
7682 private final CelValueProvider valueProvider ;
@@ -107,10 +113,11 @@ public PlannedProgram plan(CelAbstractSyntaxTree ast) throws CelEvaluationExcept
107113 .map (celBlock -> planBlock (celBlock , ctx ))
108114 .orElseGet (() -> plan (ast .getExpr (), ctx ));
109115 } catch (RuntimeException e ) {
110- throw CelEvaluationExceptionBuilder .newBuilder (e .getMessage ())
111- .setMetadata (errorMetadata , ast .getExpr ().id ())
112- .setCause (e )
113- .build ();
116+ CelEvaluationExceptionBuilder builder =
117+ e instanceof CelRuntimeException
118+ ? CelEvaluationExceptionBuilder .newBuilder ((CelRuntimeException ) e )
119+ : CelEvaluationExceptionBuilder .newBuilder (e .getMessage ()).setCause (e );
120+ throw builder .setMetadata (errorMetadata , ast .getExpr ().id ()).build ();
114121 }
115122
116123 return PlannedProgram .create (
@@ -355,6 +362,11 @@ private PlannedInterpretable planCall(CelExpr expr, PlannerContext ctx) {
355362 evaluatedArgs [1 ],
356363 celValueConverter );
357364 }
365+ PlannedInterpretable regexMatches =
366+ maybePlanRegexMatches (expr , resolvedOverload , evaluatedArgs ).orElse (null );
367+ if (regexMatches != null ) {
368+ return regexMatches ;
369+ }
358370 return EvalBinary .create (
359371 expr ,
360372 functionName ,
@@ -368,6 +380,39 @@ private PlannedInterpretable planCall(CelExpr expr, PlannerContext ctx) {
368380 }
369381 }
370382
383+ private Optional <PlannedInterpretable > maybePlanRegexMatches (
384+ CelExpr expr , CelResolvedOverload resolvedOverload , PlannedInterpretable [] evaluatedArgs ) {
385+ String overloadId = resolvedOverload .getOverloadId ();
386+ if (!overloadId .equals ("matches" ) && !overloadId .equals ("matches_string" )) {
387+ return Optional .empty ();
388+ }
389+ if (!resolvedOverload .getParameterTypes ().equals (MATCHES_PARAMETER_TYPES )) {
390+ return Optional .empty ();
391+ }
392+ if (!(evaluatedArgs [1 ] instanceof EvalConstant )) {
393+ return Optional .empty ();
394+ }
395+ Object rawConstant = ((EvalConstant ) evaluatedArgs [1 ]).constantValue ();
396+ if (!(rawConstant instanceof String )) {
397+ return Optional .empty ();
398+ }
399+ Pattern compiledPattern = RuntimeHelpers .compileRegexPattern ((String ) rawConstant , options );
400+ CelFunctionBinding binding =
401+ CelFunctionBinding .from (
402+ overloadId ,
403+ String .class ,
404+ target -> RuntimeHelpers .matches (target , compiledPattern , options ));
405+ CelResolvedOverload unaryOverload =
406+ CelResolvedOverload .of (
407+ "matches" ,
408+ overloadId ,
409+ binding .getDefinition (),
410+ binding .isStrict (),
411+ binding .getArgTypes ());
412+ return Optional .of (
413+ EvalUnary .create (expr , "matches" , unaryOverload , evaluatedArgs [0 ], celValueConverter ));
414+ }
415+
371416 private PlannedInterpretable planBlock (CelBlock celBlock , PlannerContext ctx ) {
372417 ImmutableList <CelExpr > indices = celBlock .indices ();
373418
0 commit comments