Skip to content

Commit 26c97dc

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

9 files changed

Lines changed: 271 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: 20 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",
@@ -470,8 +471,17 @@ java_library(
470471
deps = [
471472
":attribute",
472473
":eval_attribute",
474+
":eval_const",
475+
":eval_unary",
473476
":planned_interpretable",
477+
"//common:options",
474478
"//common/ast",
479+
"//common/values",
480+
"//runtime:function_binding",
481+
"//runtime:resolved_overload",
482+
"//runtime:runtime_helpers",
483+
"@maven//:com_google_guava_guava",
484+
"@maven//:com_google_re2j_re2j",
475485
],
476486
)
477487

@@ -718,6 +728,7 @@ cel_android_library(
718728
"//common/ast:ast_android",
719729
"//common/ast:cel_block_android",
720730
"//common/exceptions:overload_not_found",
731+
"//common/exceptions:runtime_exception",
721732
"//common/types:type_providers_android",
722733
"//common/types:types_android",
723734
"//common/values:cel_value_provider_android",
@@ -1137,8 +1148,17 @@ cel_android_library(
11371148
deps = [
11381149
":attribute_android",
11391150
":eval_attribute_android",
1151+
":eval_const_android",
1152+
":eval_unary_android",
11401153
":planned_interpretable_android",
1154+
"//common:options",
11411155
"//common/ast:ast_android",
1156+
"//common/values:values_android",
1157+
"//runtime:function_binding_android",
1158+
"//runtime:resolved_overload_android",
1159+
"//runtime:runtime_helpers_android",
1160+
"@maven//:com_google_re2j_re2j",
1161+
"@maven_android//:com_google_guava_guava",
11421162
],
11431163
)
11441164

‎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/PlannerHelpers.java‎

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,20 @@
1414

1515
package dev.cel.runtime.planner;
1616

17+
import com.google.common.collect.ImmutableList;
18+
import com.google.re2j.Pattern;
19+
import dev.cel.common.CelOptions;
1720
import dev.cel.common.ast.CelConstant;
21+
import dev.cel.common.ast.CelExpr;
22+
import dev.cel.common.values.CelValueConverter;
23+
import dev.cel.runtime.CelFunctionBinding;
24+
import dev.cel.runtime.CelResolvedOverload;
25+
import dev.cel.runtime.RuntimeHelpers;
26+
import java.util.Optional;
1827

1928
final class PlannerHelpers {
29+
private static final ImmutableList<Class<?>> MATCHES_PARAMETER_TYPES =
30+
ImmutableList.of(String.class, String.class);
2031

2132
static Attribute resolveBaseAttribute(
2233
PlannedInterpretable operand, AttributeFactory attributeFactory) {
@@ -47,5 +58,42 @@ static Object resolveConstant(CelConstant celConstant) {
4758
}
4859
}
4960

61+
static Optional<PlannedInterpretable> maybePlanRegexMatches(
62+
CelExpr expr,
63+
CelResolvedOverload resolvedOverload,
64+
PlannedInterpretable[] evaluatedArgs,
65+
CelOptions options,
66+
CelValueConverter celValueConverter) {
67+
String overloadId = resolvedOverload.getOverloadId();
68+
if (!overloadId.equals("matches") && !overloadId.equals("matches_string")) {
69+
return Optional.empty();
70+
}
71+
if (!resolvedOverload.getParameterTypes().equals(MATCHES_PARAMETER_TYPES)) {
72+
return Optional.empty();
73+
}
74+
if (!(evaluatedArgs[1] instanceof EvalConstant)) {
75+
return Optional.empty();
76+
}
77+
Object rawConstant = ((EvalConstant) evaluatedArgs[1]).constantValue();
78+
if (!(rawConstant instanceof String)) {
79+
return Optional.empty();
80+
}
81+
Pattern compiledPattern = RuntimeHelpers.compileRegexPattern((String) rawConstant, options);
82+
CelFunctionBinding binding =
83+
CelFunctionBinding.from(
84+
overloadId,
85+
String.class,
86+
target -> RuntimeHelpers.matches(target, compiledPattern, options));
87+
CelResolvedOverload unaryOverload =
88+
CelResolvedOverload.of(
89+
"matches",
90+
overloadId,
91+
binding.getDefinition(),
92+
binding.isStrict(),
93+
binding.getArgTypes());
94+
return Optional.of(
95+
EvalUnary.create(expr, "matches", unaryOverload, evaluatedArgs[0], celValueConverter));
96+
}
97+
5098
private PlannerHelpers() {}
5199
}

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

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import dev.cel.common.ast.CelExpr.ExprKind.Kind;
4444
import dev.cel.common.ast.CelReference;
4545
import dev.cel.common.exceptions.CelOverloadNotFoundException;
46+
import dev.cel.common.exceptions.CelRuntimeException;
4647
import dev.cel.common.types.CelKind;
4748
import dev.cel.common.types.CelType;
4849
import dev.cel.common.types.CelTypeProvider;
@@ -107,10 +108,15 @@ public PlannedProgram plan(CelAbstractSyntaxTree ast) throws CelEvaluationExcept
107108
.map(celBlock -> planBlock(celBlock, ctx))
108109
.orElseGet(() -> plan(ast.getExpr(), ctx));
109110
} catch (RuntimeException e) {
110-
throw CelEvaluationExceptionBuilder.newBuilder(e.getMessage())
111-
.setMetadata(errorMetadata, ast.getExpr().id())
112-
.setCause(e)
113-
.build();
111+
// Preserve specific CelErrorCode (e.g., INVALID_ARGUMENT, OVERLOAD_NOT_FOUND) from
112+
// plan-time validation failures.
113+
CelEvaluationExceptionBuilder builder;
114+
if (e instanceof CelRuntimeException) {
115+
builder = CelEvaluationExceptionBuilder.newBuilder((CelRuntimeException) e);
116+
} else {
117+
builder = CelEvaluationExceptionBuilder.newBuilder(e.getMessage()).setCause(e);
118+
}
119+
throw builder.setMetadata(errorMetadata, ast.getExpr().id()).build();
114120
}
115121

116122
return PlannedProgram.create(
@@ -355,6 +361,13 @@ private PlannedInterpretable planCall(CelExpr expr, PlannerContext ctx) {
355361
evaluatedArgs[1],
356362
celValueConverter);
357363
}
364+
PlannedInterpretable regexMatches =
365+
PlannerHelpers.maybePlanRegexMatches(
366+
expr, resolvedOverload, evaluatedArgs, options, celValueConverter)
367+
.orElse(null);
368+
if (regexMatches != null) {
369+
return regexMatches;
370+
}
358371
return EvalBinary.create(
359372
expr,
360373
functionName,

‎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)