Skip to content

Commit 4cacabb

Browse files
l46kokcopybara-github
authored andcommitted
Add new interfaces for ProgramPlanner, plan constants
PiperOrigin-RevId: 831032679
1 parent 0392908 commit 4cacabb

File tree

7 files changed

+472
-0
lines changed

7 files changed

+472
-0
lines changed

runtime/planner/BUILD.bazel

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
load("@rules_java//java:defs.bzl", "java_library")
2+
3+
package(
4+
default_applicable_licenses = ["//:license"],
5+
default_visibility = ["//:internal"],
6+
)
7+
8+
java_library(
9+
name = "program_planner",
10+
exports = ["//runtime/src/main/java/dev/cel/runtime/planner:program_planner"],
11+
)
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
load("@rules_java//java:defs.bzl", "java_library")
2+
3+
package(
4+
default_applicable_licenses = ["//:license"],
5+
default_visibility = [
6+
"//runtime/planner:__pkg__",
7+
],
8+
)
9+
10+
java_library(
11+
name = "program_planner",
12+
srcs = ["ProgramPlanner.java"],
13+
tags = [
14+
],
15+
deps = [
16+
":eval_const",
17+
":planned_program",
18+
"//:auto_value",
19+
"//common:cel_ast",
20+
"//common/annotations",
21+
"//common/ast",
22+
"//common/types:type_providers",
23+
"//runtime:evaluation_exception",
24+
"//runtime:evaluation_exception_builder",
25+
"//runtime:interpretable",
26+
"//runtime:program",
27+
"@maven//:com_google_code_findbugs_annotations",
28+
"@maven//:com_google_errorprone_error_prone_annotations",
29+
"@maven//:com_google_guava_guava",
30+
],
31+
)
32+
33+
java_library(
34+
name = "planned_program",
35+
srcs = ["PlannedProgram.java"],
36+
deps = [
37+
"//:auto_value",
38+
"//runtime:evaluation_exception",
39+
"//runtime:function_resolver",
40+
"//runtime:interpretable",
41+
"//runtime:program",
42+
"@maven//:com_google_errorprone_error_prone_annotations",
43+
],
44+
)
45+
46+
java_library(
47+
name = "eval_const",
48+
srcs = ["EvalConstant.java"],
49+
deps = [
50+
"//common/values",
51+
"//common/values:cel_byte_string",
52+
"//runtime:evaluation_listener",
53+
"//runtime:function_resolver",
54+
"//runtime:interpretable",
55+
"@maven//:com_google_errorprone_error_prone_annotations",
56+
"@maven//:com_google_guava_guava",
57+
],
58+
)
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package dev.cel.runtime.planner;
16+
17+
import com.google.common.primitives.UnsignedLong;
18+
import com.google.errorprone.annotations.Immutable;
19+
import dev.cel.common.values.CelByteString;
20+
import dev.cel.common.values.NullValue;
21+
import dev.cel.runtime.CelEvaluationListener;
22+
import dev.cel.runtime.CelFunctionResolver;
23+
import dev.cel.runtime.GlobalResolver;
24+
import dev.cel.runtime.Interpretable;
25+
26+
@Immutable
27+
final class EvalConstant implements Interpretable {
28+
29+
// Pre-allocation of common constants
30+
private static final EvalConstant NULL_VALUE = new EvalConstant(NullValue.NULL_VALUE);
31+
private static final EvalConstant TRUE = new EvalConstant(true);
32+
private static final EvalConstant FALSE = new EvalConstant(false);
33+
private static final EvalConstant ZERO = new EvalConstant(0L);
34+
private static final EvalConstant ONE = new EvalConstant(1L);
35+
private static final EvalConstant UNSIGNED_ZERO = new EvalConstant(UnsignedLong.ZERO);
36+
private static final EvalConstant UNSIGNED_ONE = new EvalConstant(UnsignedLong.ONE);
37+
private static final EvalConstant EMPTY_STRING = new EvalConstant("");
38+
private static final EvalConstant EMPTY_BYTES = new EvalConstant(CelByteString.EMPTY);
39+
40+
@SuppressWarnings("Immutable") // Known CEL constants that aren't mutated are stored
41+
private final Object constant;
42+
43+
@Override
44+
public Object eval(GlobalResolver resolver) {
45+
return constant;
46+
}
47+
48+
@Override
49+
public Object eval(GlobalResolver resolver, CelEvaluationListener listener) {
50+
return constant;
51+
}
52+
53+
@Override
54+
public Object eval(GlobalResolver resolver, CelFunctionResolver lateBoundFunctionResolver) {
55+
return constant;
56+
}
57+
58+
@Override
59+
public Object eval(
60+
GlobalResolver resolver,
61+
CelFunctionResolver lateBoundFunctionResolver,
62+
CelEvaluationListener listener) {
63+
return constant;
64+
}
65+
66+
static EvalConstant create(boolean value) {
67+
return value ? TRUE : FALSE;
68+
}
69+
70+
static EvalConstant create(String value) {
71+
if (value.isEmpty()) {
72+
return EMPTY_STRING;
73+
}
74+
75+
return new EvalConstant(value);
76+
}
77+
78+
static EvalConstant create(long value) {
79+
if (value == 0L) {
80+
return ZERO;
81+
} else if (value == 1L) {
82+
return ONE;
83+
}
84+
85+
return new EvalConstant(Long.valueOf(value));
86+
}
87+
88+
static EvalConstant create(double value) {
89+
return new EvalConstant(Double.valueOf(value));
90+
}
91+
92+
static EvalConstant create(UnsignedLong unsignedLong) {
93+
if (unsignedLong.longValue() == 0L) {
94+
return UNSIGNED_ZERO;
95+
} else if (unsignedLong.longValue() == 1L) {
96+
return UNSIGNED_ONE;
97+
}
98+
99+
return new EvalConstant(unsignedLong);
100+
}
101+
102+
static EvalConstant create(NullValue unused) {
103+
return NULL_VALUE;
104+
}
105+
106+
static EvalConstant create(CelByteString byteString) {
107+
if (byteString.isEmpty()) {
108+
return EMPTY_BYTES;
109+
}
110+
return new EvalConstant(byteString);
111+
}
112+
113+
private EvalConstant(Object constant) {
114+
this.constant = constant;
115+
}
116+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package dev.cel.runtime.planner;
16+
17+
import com.google.auto.value.AutoValue;
18+
import com.google.errorprone.annotations.Immutable;
19+
import dev.cel.runtime.CelEvaluationException;
20+
import dev.cel.runtime.CelFunctionResolver;
21+
import dev.cel.runtime.GlobalResolver;
22+
import dev.cel.runtime.Interpretable;
23+
import dev.cel.runtime.Program;
24+
import java.util.Map;
25+
26+
@Immutable
27+
@AutoValue
28+
abstract class PlannedProgram implements Program {
29+
abstract Interpretable interpretable();
30+
31+
@Override
32+
public Object eval() throws CelEvaluationException {
33+
return interpretable().eval(GlobalResolver.EMPTY);
34+
}
35+
36+
@Override
37+
public Object eval(Map<String, ?> mapValue) throws CelEvaluationException {
38+
throw new UnsupportedOperationException("Not yet implemented");
39+
}
40+
41+
@Override
42+
public Object eval(Map<String, ?> mapValue, CelFunctionResolver lateBoundFunctionResolver)
43+
throws CelEvaluationException {
44+
throw new UnsupportedOperationException("Late bound functions not supported yet");
45+
}
46+
47+
static Program create(Interpretable interpretable) {
48+
return new AutoValue_PlannedProgram(interpretable);
49+
}
50+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package dev.cel.runtime.planner;
16+
17+
import com.google.auto.value.AutoValue;
18+
import com.google.common.collect.ImmutableMap;
19+
import javax.annotation.concurrent.ThreadSafe;
20+
import dev.cel.common.CelAbstractSyntaxTree;
21+
import dev.cel.common.annotations.Internal;
22+
import dev.cel.common.ast.CelConstant;
23+
import dev.cel.common.ast.CelExpr;
24+
import dev.cel.common.ast.CelReference;
25+
import dev.cel.common.types.CelType;
26+
import dev.cel.runtime.CelEvaluationException;
27+
import dev.cel.runtime.CelEvaluationExceptionBuilder;
28+
import dev.cel.runtime.Interpretable;
29+
import dev.cel.runtime.Program;
30+
31+
/**
32+
* {@code ProgramPlanner} resolves functions, types, and identifiers at plan time given a
33+
* parsed-only or a type-checked expression.
34+
*/
35+
@ThreadSafe
36+
@Internal
37+
public final class ProgramPlanner {
38+
39+
/**
40+
* Plans a {@link Program} from the provided parsed-only or type-checked {@link
41+
* CelAbstractSyntaxTree}.
42+
*/
43+
public Program plan(CelAbstractSyntaxTree ast) throws CelEvaluationException {
44+
Interpretable plannedInterpretable;
45+
try {
46+
plannedInterpretable = plan(ast.getExpr(), PlannerContext.create(ast));
47+
} catch (RuntimeException e) {
48+
throw CelEvaluationExceptionBuilder.newBuilder(e.getMessage()).setCause(e).build();
49+
}
50+
51+
return PlannedProgram.create(plannedInterpretable);
52+
}
53+
54+
private Interpretable plan(CelExpr celExpr, PlannerContext unused) {
55+
switch (celExpr.getKind()) {
56+
case CONSTANT:
57+
return planConstant(celExpr.constant());
58+
case NOT_SET:
59+
throw new UnsupportedOperationException("Unsupported kind: " + celExpr.getKind());
60+
default:
61+
throw new IllegalArgumentException("Not yet implemented kind: " + celExpr.getKind());
62+
}
63+
}
64+
65+
private Interpretable planConstant(CelConstant celConstant) {
66+
switch (celConstant.getKind()) {
67+
case NULL_VALUE:
68+
return EvalConstant.create(celConstant.nullValue());
69+
case BOOLEAN_VALUE:
70+
return EvalConstant.create(celConstant.booleanValue());
71+
case INT64_VALUE:
72+
return EvalConstant.create(celConstant.int64Value());
73+
case UINT64_VALUE:
74+
return EvalConstant.create(celConstant.uint64Value());
75+
case DOUBLE_VALUE:
76+
return EvalConstant.create(celConstant.doubleValue());
77+
case STRING_VALUE:
78+
return EvalConstant.create(celConstant.stringValue());
79+
case BYTES_VALUE:
80+
return EvalConstant.create(celConstant.bytesValue());
81+
default:
82+
throw new IllegalStateException("Unsupported kind: " + celConstant.getKind());
83+
}
84+
}
85+
86+
@AutoValue
87+
abstract static class PlannerContext {
88+
89+
abstract ImmutableMap<Long, CelReference> referenceMap();
90+
91+
abstract ImmutableMap<Long, CelType> typeMap();
92+
93+
private static PlannerContext create(CelAbstractSyntaxTree ast) {
94+
return new AutoValue_ProgramPlanner_PlannerContext(ast.getReferenceMap(), ast.getTypeMap());
95+
}
96+
}
97+
98+
public static ProgramPlanner newPlanner() {
99+
return new ProgramPlanner();
100+
}
101+
102+
private ProgramPlanner() {}
103+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
load("@rules_java//java:defs.bzl", "java_library")
2+
load("//:testing.bzl", "junit4_test_suites")
3+
4+
package(
5+
default_applicable_licenses = ["//:license"],
6+
default_testonly = True,
7+
)
8+
9+
java_library(
10+
name = "tests",
11+
testonly = 1,
12+
srcs = glob(
13+
["*.java"],
14+
),
15+
deps = [
16+
"//:java_truth",
17+
"//common:cel_ast",
18+
"//common:cel_source",
19+
"//common/ast",
20+
"//common/values",
21+
"//common/values:cel_byte_string",
22+
"//compiler",
23+
"//compiler:compiler_builder",
24+
"//runtime",
25+
"//runtime:program",
26+
"//runtime/planner:program_planner",
27+
"@maven//:com_google_guava_guava",
28+
"@maven//:com_google_testparameterinjector_test_parameter_injector",
29+
"@maven//:junit_junit",
30+
],
31+
)
32+
33+
junit4_test_suites(
34+
name = "test_suites",
35+
sizes = [
36+
"small",
37+
],
38+
src_dir = "src/test/java",
39+
deps = [
40+
":tests",
41+
],
42+
)

0 commit comments

Comments
 (0)