Skip to content

Commit 37fd73f

Browse files
l46kokcopybara-github
authored andcommitted
No public description
PiperOrigin-RevId: 996768728
1 parent 4264e97 commit 37fd73f

8 files changed

Lines changed: 243 additions & 27 deletions

File tree

‎runtime/src/main/java/dev/cel/runtime/BUILD.bazel‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,7 @@ cel_android_library(
427427
"//common/annotations",
428428
"//common/exceptions:divide_by_zero",
429429
"//common/exceptions:index_out_of_bounds",
430+
"//common/exceptions:invalid_argument",
430431
"//common/exceptions:numeric_overflow",
431432
"//common/internal:converter",
432433
"//common/values:values_android",
@@ -451,6 +452,7 @@ java_library(
451452
"//common/annotations",
452453
"//common/exceptions:divide_by_zero",
453454
"//common/exceptions:index_out_of_bounds",
455+
"//common/exceptions:invalid_argument",
454456
"//common/exceptions:numeric_overflow",
455457
"//common/internal:converter",
456458
"//common/values",

‎runtime/src/main/java/dev/cel/runtime/RuntimeHelpers.java‎

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@
2323
import com.google.protobuf.Duration;
2424
import com.google.protobuf.MessageLiteOrBuilder;
2525
import com.google.re2j.Pattern;
26+
import com.google.re2j.PatternSyntaxException;
2627
import dev.cel.common.CelOptions;
2728
import dev.cel.common.annotations.Internal;
2829
import dev.cel.common.exceptions.CelDivideByZeroException;
2930
import dev.cel.common.exceptions.CelIndexOutOfBoundsException;
31+
import dev.cel.common.exceptions.CelInvalidArgumentException;
3032
import dev.cel.common.exceptions.CelNumericOverflowException;
3133
import dev.cel.common.internal.Converter;
3234
import dev.cel.common.values.NullValue;
@@ -76,16 +78,28 @@ public static java.time.Duration createJavaDurationFromString(String d) {
7678
}
7779
}
7880

79-
public static boolean matches(String string, String regexp, CelOptions celOptions) {
80-
Pattern pattern = Pattern.compile(regexp);
81+
/**
82+
* Compiles the given RE2J regex pattern string and validates it against {@link
83+
* CelOptions#maxRegexProgramSize()}.
84+
*/
85+
public static Pattern compileRegexPattern(String regexp, CelOptions celOptions) {
86+
Pattern pattern;
87+
try {
88+
pattern = Pattern.compile(regexp);
89+
} catch (PatternSyntaxException e) {
90+
throw new CelInvalidArgumentException(e);
91+
}
8192
int maxProgramSize = celOptions.maxRegexProgramSize();
8293
if (maxProgramSize >= 0 && pattern.programSize() > maxProgramSize) {
83-
throw new IllegalArgumentException(
94+
throw new CelInvalidArgumentException(
8495
String.format(
8596
"Regex pattern exceeds allowed program size. Allowed: %d, Provided: %d",
8697
maxProgramSize, pattern.programSize()));
8798
}
99+
return pattern;
100+
}
88101

102+
public static boolean matches(String string, Pattern pattern, CelOptions celOptions) {
89103
if (!celOptions.enableRegexPartialMatch()) {
90104
// Uses re2 for consistency across languages.
91105
return pattern.matcher(string).matches();
@@ -95,6 +109,10 @@ public static boolean matches(String string, String regexp, CelOptions celOption
95109
return pattern.matcher(string).find();
96110
}
97111

112+
public static boolean matches(String string, String regexp, CelOptions celOptions) {
113+
return matches(string, compileRegexPattern(regexp, celOptions), celOptions);
114+
}
115+
98116
/** Concatenates two lists into a new list. */
99117
public static <E> List<E> concat(List<E> first, List<E> second) {
100118
if (first instanceof ConcatenatedListView) {

‎runtime/src/main/java/dev/cel/runtime/planner/BUILD.bazel‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ java_library(
5353
"//common/ast",
5454
"//common/ast:cel_block",
5555
"//common/exceptions:overload_not_found",
56+
"//common/exceptions:runtime_exception",
5657
"//common/types",
5758
"//common/types:type_providers",
5859
"//common/values",
@@ -61,12 +62,15 @@ java_library(
6162
"//runtime:dispatcher",
6263
"//runtime:evaluation_exception",
6364
"//runtime:evaluation_exception_builder",
65+
"//runtime:function_binding",
6466
"//runtime:function_overload",
6567
"//runtime:resolved_overload",
6668
"//runtime:runtime_equality",
69+
"//runtime:runtime_helpers",
6770
"@maven//:com_google_code_findbugs_annotations",
6871
"@maven//:com_google_errorprone_error_prone_annotations",
6972
"@maven//:com_google_guava_guava",
73+
"@maven//:com_google_re2j_re2j",
7074
"@maven//:org_jspecify_jspecify",
7175
],
7276
)
@@ -718,6 +722,7 @@ cel_android_library(
718722
"//common/ast:ast_android",
719723
"//common/ast:cel_block_android",
720724
"//common/exceptions:overload_not_found",
725+
"//common/exceptions:runtime_exception",
721726
"//common/types:type_providers_android",
722727
"//common/types:types_android",
723728
"//common/values:cel_value_provider_android",
@@ -726,11 +731,14 @@ cel_android_library(
726731
"//runtime:dispatcher_android",
727732
"//runtime:evaluation_exception",
728733
"//runtime:evaluation_exception_builder",
734+
"//runtime:function_binding_android",
729735
"//runtime:function_overload_android",
730736
"//runtime:resolved_overload_android",
731737
"//runtime:runtime_equality_android",
738+
"//runtime:runtime_helpers_android",
732739
"@maven//:com_google_errorprone_error_prone_annotations",
733740
"@maven//:com_google_guava_guava",
741+
"@maven//:com_google_re2j_re2j",
734742
"@maven//:org_jspecify_jspecify",
735743
"@maven_android//:com_google_guava_guava",
736744
],

‎runtime/src/main/java/dev/cel/runtime/planner/EvalConstant.java‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ Object evalInternal(GlobalResolver resolver, ExecutionFrame frame) {
2929
return constant;
3030
}
3131

32+
Object constantValue() {
33+
return constant;
34+
}
35+
3236
static EvalConstant create(CelExpr expr, Object value) {
3337
return new EvalConstant(expr, value);
3438
}

‎runtime/src/main/java/dev/cel/runtime/planner/ProgramPlanner.java‎

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import com.google.common.util.concurrent.ListeningExecutorService;
2626
import com.google.errorprone.annotations.CheckReturnValue;
2727
import com.google.errorprone.annotations.Immutable;
28+
import com.google.re2j.Pattern;
2829
import dev.cel.common.CelAbstractSyntaxTree;
2930
import dev.cel.common.CelContainer;
3031
import dev.cel.common.CelOptions;
@@ -43,6 +44,7 @@
4344
import dev.cel.common.ast.CelExpr.ExprKind.Kind;
4445
import dev.cel.common.ast.CelReference;
4546
import dev.cel.common.exceptions.CelOverloadNotFoundException;
47+
import dev.cel.common.exceptions.CelRuntimeException;
4648
import dev.cel.common.types.CelKind;
4749
import dev.cel.common.types.CelType;
4850
import dev.cel.common.types.CelTypeProvider;
@@ -54,9 +56,11 @@
5456
import dev.cel.runtime.CelAsyncFunctionOverload;
5557
import dev.cel.runtime.CelEvaluationException;
5658
import dev.cel.runtime.CelEvaluationExceptionBuilder;
59+
import dev.cel.runtime.CelFunctionBinding;
5760
import dev.cel.runtime.CelResolvedOverload;
5861
import dev.cel.runtime.DefaultDispatcher;
5962
import dev.cel.runtime.RuntimeEquality;
63+
import dev.cel.runtime.RuntimeHelpers;
6064
import java.util.Arrays;
6165
import java.util.HashMap;
6266
import java.util.NoSuchElementException;
@@ -71,6 +75,8 @@
7175
@Internal
7276
public 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

‎runtime/src/main/java/dev/cel/runtime/standard/BUILD.bazel‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1045,7 +1045,6 @@ java_library(
10451045
deps = [
10461046
":standard_overload",
10471047
"//common:options",
1048-
"//common/exceptions:invalid_argument",
10491048
"//runtime:function_binding",
10501049
"//runtime:runtime_equality",
10511050
"//runtime:runtime_helpers",
@@ -1063,7 +1062,6 @@ cel_android_library(
10631062
":standard_function_android",
10641063
":standard_overload_android",
10651064
"//common:options",
1066-
"//common/exceptions:invalid_argument",
10671065
"//runtime:function_binding_android",
10681066
"//runtime:runtime_equality_android",
10691067
"//runtime:runtime_helpers_android",

‎runtime/src/main/java/dev/cel/runtime/standard/MatchesFunction.java‎

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
import com.google.common.collect.ImmutableSet;
1818
import dev.cel.common.CelOptions;
19-
import dev.cel.common.exceptions.CelInvalidArgumentException;
2019
import dev.cel.runtime.CelFunctionBinding;
2120
import dev.cel.runtime.RuntimeEquality;
2221
import dev.cel.runtime.RuntimeHelpers;
@@ -46,27 +45,17 @@ public enum MatchesOverload implements CelStandardOverload {
4645
"matches",
4746
String.class,
4847
String.class,
49-
(String string, String regexp) -> {
50-
try {
51-
return RuntimeHelpers.matches(string, regexp, celOptions);
52-
} catch (RuntimeException e) {
53-
throw new CelInvalidArgumentException(e);
54-
}
55-
})),
48+
(String string, String regexp) ->
49+
RuntimeHelpers.matches(string, regexp, celOptions))),
5650
// Duplicate receiver-style matches overload.
5751
MATCHES_STRING(
5852
(celOptions, runtimeEquality) ->
5953
CelFunctionBinding.from(
6054
"matches_string",
6155
String.class,
6256
String.class,
63-
(String string, String regexp) -> {
64-
try {
65-
return RuntimeHelpers.matches(string, regexp, celOptions);
66-
} catch (RuntimeException e) {
67-
throw new CelInvalidArgumentException(e);
68-
}
69-
})),
57+
(String string, String regexp) ->
58+
RuntimeHelpers.matches(string, regexp, celOptions))),
7059
;
7160

7261
private final CelStandardOverload standardOverload;

0 commit comments

Comments
 (0)