Skip to content

Commit e1edfe2

Browse files
l46kokcopybara-github
authored andcommitted
Add CelCompilerTool java binary and compile_cel bzl library
PiperOrigin-RevId: 726254974
1 parent 59332cb commit e1edfe2

File tree

13 files changed

+410
-0
lines changed

13 files changed

+410
-0
lines changed

WORKSPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ maven_install(
140140
"com.google.truth.extensions:truth-java8-extension:1.4.4",
141141
"com.google.truth.extensions:truth-proto-extension:1.4.4",
142142
"com.google.truth:truth:1.4.4",
143+
"info.picocli:picocli:4.7.6",
143144
"org.antlr:antlr4-runtime:" + ANTLR4_VERSION,
144145
"org.jspecify:jspecify:1.0.0",
145146
"org.threeten:threeten-extra:1.8.0",

common/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ java_library(
3939

4040
java_library(
4141
name = "error_codes",
42+
# used_by_android
4243
exports = ["//common/src/main/java/dev/cel/common:error_codes"],
4344
)
4445

@@ -86,6 +87,7 @@ java_library(
8687

8788
java_library(
8889
name = "cel_exception",
90+
# used_by_android
8991
visibility = ["//visibility:public"],
9092
exports = ["//common/src/main/java/dev/cel/common:cel_exception"],
9193
)

common/annotations/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ package(
77

88
java_library(
99
name = "annotations",
10+
# used_by_android
1011
exports = ["//common/src/main/java/dev/cel/common/annotations"],
1112
)

common/internal/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ cel_android_library(
2323

2424
java_library(
2525
name = "converter",
26+
# used_by_android
2627
exports = ["//common/src/main/java/dev/cel/common/internal:converter"],
2728
)
2829

@@ -78,6 +79,7 @@ java_library(
7879

7980
java_library(
8081
name = "safe_string_formatter",
82+
# used_by_android
8183
exports = ["//common/src/main/java/dev/cel/common/internal:safe_string_formatter"],
8284
)
8385

common/src/main/java/dev/cel/common/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ java_library(
7777
java_library(
7878
name = "cel_exception",
7979
srcs = ["CelException.java"],
80+
# used_by_android
8081
tags = [
8182
],
8283
visibility = ["//visibility:public"],
@@ -135,6 +136,7 @@ java_library(
135136
java_library(
136137
name = "error_codes",
137138
srcs = ["CelErrorCode.java"],
139+
# used_by_android
138140
tags = [
139141
],
140142
)

common/src/main/java/dev/cel/common/annotations/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ ANNOTATION_SOURCES = [
1717
java_library(
1818
name = "annotations",
1919
srcs = ANNOTATION_SOURCES,
20+
# used_by_android
2021
tags = [
2122
],
2223
)

common/src/main/java/dev/cel/common/internal/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ java_library(
100100
"BidiConverter.java",
101101
"Converter.java",
102102
],
103+
# used_by_android
103104
tags = [
104105
],
105106
deps = [
@@ -264,6 +265,7 @@ java_library(
264265
java_library(
265266
name = "safe_string_formatter",
266267
srcs = ["SafeStringFormatter.java"],
268+
# used_by_android
267269
tags = [
268270
],
269271
deps = [
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
load("@rules_java//java:defs.bzl", "java_binary")
2+
3+
package(
4+
default_applicable_licenses = [
5+
"//:license",
6+
],
7+
default_visibility = [
8+
"//compiler/tools:__pkg__",
9+
],
10+
)
11+
12+
java_binary(
13+
name = "cel_compiler_tool",
14+
srcs = ["CelCompilerTool.java"],
15+
main_class = "dev.cel.compiler.tools.CelCompilerTool",
16+
neverlink = 1,
17+
deps = [
18+
"//common",
19+
"//common:compiler_common",
20+
"//common:options",
21+
"//common:proto_ast",
22+
"//compiler",
23+
"//compiler:compiler_builder",
24+
"//extensions",
25+
"//extensions:optional_library",
26+
"//parser:macro",
27+
"@cel_spec//proto/cel/expr:checked_java_proto",
28+
"@maven//:com_google_guava_guava",
29+
"@maven//:com_google_protobuf_protobuf_java",
30+
"@maven//:info_picocli_picocli",
31+
],
32+
)
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
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.compiler.tools;
16+
17+
import dev.cel.expr.CheckedExpr;
18+
import com.google.common.collect.ImmutableSet;
19+
import com.google.common.io.Files;
20+
import com.google.protobuf.DescriptorProtos.FileDescriptorSet;
21+
import com.google.protobuf.Descriptors.FileDescriptor;
22+
import com.google.protobuf.ExtensionRegistry;
23+
import dev.cel.common.CelAbstractSyntaxTree;
24+
import dev.cel.common.CelDescriptorUtil;
25+
import dev.cel.common.CelOptions;
26+
import dev.cel.common.CelProtoAbstractSyntaxTree;
27+
import dev.cel.common.CelValidationException;
28+
import dev.cel.compiler.CelCompiler;
29+
import dev.cel.compiler.CelCompilerBuilder;
30+
import dev.cel.compiler.CelCompilerFactory;
31+
import dev.cel.extensions.CelExtensions;
32+
import dev.cel.extensions.CelOptionalLibrary;
33+
import dev.cel.parser.CelStandardMacro;
34+
import java.io.File;
35+
import java.io.FileOutputStream;
36+
import java.io.IOException;
37+
import java.nio.file.Path;
38+
import java.nio.file.Paths;
39+
import java.util.concurrent.Callable;
40+
import picocli.CommandLine;
41+
import picocli.CommandLine.Option;
42+
43+
/**
44+
* CelCompilerTool is a binary that takes a CEL expression in string, compiles it into a
45+
* dev.cel.expr.CheckedExpr protobuf message, then writes the content to a .binary pb file.
46+
*/
47+
final class CelCompilerTool implements Callable<Integer> {
48+
49+
@Option(
50+
names = {"--cel_expression"},
51+
description = "CEL expression")
52+
private String celExpression = "";
53+
54+
@Option(
55+
names = {"--transitive_descriptor_set"},
56+
description = "Path to the transitive set of descriptors")
57+
private String transitiveDescriptorSetPath = "";
58+
59+
@Option(
60+
names = {"--output"},
61+
description = "Output path for the compiled binarypb")
62+
private String output = "";
63+
64+
private static final CelOptions CEL_OPTIONS = CelOptions.DEFAULT;
65+
66+
private static FileDescriptorSet load(String descriptorSetPath) {
67+
try {
68+
byte[] descriptorBytes = Files.toByteArray(new File(descriptorSetPath));
69+
return FileDescriptorSet.parseFrom(descriptorBytes, ExtensionRegistry.getEmptyRegistry());
70+
} catch (IOException e) {
71+
throw new IllegalArgumentException(
72+
"Failed to load FileDescriptorSet from path: " + descriptorSetPath, e);
73+
}
74+
}
75+
76+
private static CelAbstractSyntaxTree compile(
77+
String expression, String transitiveDescriptorSetPath) throws CelValidationException {
78+
CelCompilerBuilder compilerBuilder =
79+
CelCompilerFactory.standardCelCompilerBuilder()
80+
.setOptions(CEL_OPTIONS)
81+
.setStandardMacros(CelStandardMacro.STANDARD_MACROS)
82+
.addLibraries(
83+
CelExtensions.bindings(),
84+
CelExtensions.encoders(),
85+
CelExtensions.math(CEL_OPTIONS),
86+
CelExtensions.lists(),
87+
CelExtensions.protos(),
88+
CelExtensions.strings(),
89+
CelOptionalLibrary.INSTANCE);
90+
if (!transitiveDescriptorSetPath.isEmpty()) {
91+
ImmutableSet<FileDescriptor> transitiveFileDescriptors =
92+
CelDescriptorUtil.getFileDescriptorsFromFileDescriptorSet(
93+
load(transitiveDescriptorSetPath));
94+
compilerBuilder.addFileTypes(transitiveFileDescriptors);
95+
}
96+
97+
CelCompiler celCompiler = compilerBuilder.build();
98+
99+
return celCompiler.compile(expression).getAst();
100+
}
101+
102+
private static void writeCheckedExpr(CelAbstractSyntaxTree ast, String filePath)
103+
throws IOException {
104+
CheckedExpr checkedExpr = CelProtoAbstractSyntaxTree.fromCelAst(ast).toCheckedExpr();
105+
Path path = Paths.get(filePath);
106+
try (FileOutputStream output = new FileOutputStream(path.toFile())) {
107+
checkedExpr.writeTo(output);
108+
}
109+
}
110+
111+
@Override
112+
public Integer call() {
113+
try {
114+
CelAbstractSyntaxTree ast = compile(celExpression, transitiveDescriptorSetPath);
115+
writeCheckedExpr(ast, output);
116+
} catch (Exception e) {
117+
String errorMessage =
118+
String.format(
119+
"Expression [%s] failed to compile. Reason: %s", celExpression, e.getMessage());
120+
System.err.print(errorMessage);
121+
return -1;
122+
}
123+
124+
return 0;
125+
}
126+
127+
public static void main(String[] args) {
128+
CelCompilerTool compilerTool = new CelCompilerTool();
129+
CommandLine cmd = new CommandLine(compilerTool);
130+
cmd.setTrimQuotes(false);
131+
cmd.parseArgs(args);
132+
133+
int exitCode = cmd.execute(args);
134+
System.exit(exitCode);
135+
}
136+
137+
CelCompilerTool() {}
138+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
load("@rules_java//java:defs.bzl", "java_library")
2+
load("//:testing.bzl", "junit4_test_suites")
3+
load("//compiler/tools:compile_cel.bzl", "compile_cel")
4+
5+
package(default_applicable_licenses = [
6+
"//:license",
7+
])
8+
9+
compile_cel(
10+
name = "compiled_hello_world",
11+
expression = "'hello world'",
12+
)
13+
14+
compile_cel(
15+
name = "compiled_comprehension",
16+
expression = "[1,2,3].map(x, x + 1)",
17+
)
18+
19+
compile_cel(
20+
name = "compiled_proto_message",
21+
expression = "cel.expr.conformance.proto2.TestAllTypes{single_int32: 1}",
22+
proto_srcs = ["@cel_spec//proto/cel/expr/conformance/proto2:test_all_types_proto"],
23+
)
24+
25+
compile_cel(
26+
name = "compiled_extensions",
27+
expression = "cel.bind(x, 10, math.greatest([1,x])) < int(' 11 '.trim()) && optional.none().orValue(true) && [].flatten() == []",
28+
proto_srcs = ["@cel_spec//proto/cel/expr/conformance/proto2:test_all_types_proto"],
29+
)
30+
31+
filegroup(
32+
name = "compiled_exprs",
33+
srcs = [
34+
":compiled_comprehension",
35+
":compiled_extensions",
36+
":compiled_hello_world",
37+
":compiled_proto_message",
38+
],
39+
)
40+
41+
java_library(
42+
name = "tests",
43+
testonly = True,
44+
srcs = glob(["*Test.java"]),
45+
resources = [":compiled_exprs"],
46+
deps = [
47+
"//:java_truth",
48+
"//common:cel_ast",
49+
"//common:options",
50+
"//common:proto_ast",
51+
"//extensions",
52+
"//extensions:optional_library",
53+
"//runtime",
54+
"@cel_spec//proto/cel/expr:checked_java_proto",
55+
"@cel_spec//proto/cel/expr/conformance/proto2:test_all_types_java_proto",
56+
"@maven//:com_google_guava_guava",
57+
"@maven//:com_google_protobuf_protobuf_java",
58+
"@maven//:junit_junit",
59+
],
60+
)
61+
62+
junit4_test_suites(
63+
name = "test_suites",
64+
sizes = [
65+
"small",
66+
],
67+
src_dir = "src/test/java",
68+
deps = [":tests"],
69+
)

0 commit comments

Comments
 (0)