Skip to content

Commit

Permalink
Add general interfaces for instantiating a CelOptimizer
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 563878390
  • Loading branch information
l46kok authored and copybara-github committed Sep 19, 2023
1 parent d39039e commit 73fb596
Show file tree
Hide file tree
Showing 15 changed files with 551 additions and 6 deletions.
26 changes: 26 additions & 0 deletions optimizer/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package(
default_applicable_licenses = ["//:license"],
default_visibility = ["//visibility:public"], # TODO: Expose to public
)

java_library(
name = "optimizer",
exports = ["//optimizer/src/main/java/dev/cel/optimizer"],
)

java_library(
name = "optimizer_builder",
exports = ["//optimizer/src/main/java/dev/cel/optimizer:optimizer_builder"],
)

java_library(
name = "ast_optimizer",
exports = ["//optimizer/src/main/java/dev/cel/optimizer:ast_optimizer"],
)

java_library(
name = "optimizer_impl",
testonly = 1,
visibility = ["//optimizer/src/test/java/dev/cel/optimizer:__pkg__"],
exports = ["//optimizer/src/main/java/dev/cel/optimizer:optimizer_impl"],
)
71 changes: 71 additions & 0 deletions optimizer/src/main/java/dev/cel/optimizer/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package(
default_applicable_licenses = ["//:license"],
default_visibility = [
"//visibility:public",
],
)

java_library(
name = "optimizer",
srcs = [
"CelOptimizerFactory.java",
],
tags = [
],
deps = [
":optimizer_impl",
"//bundle:cel",
"//checker:checker_builder",
"//compiler",
"//compiler:compiler_builder",
"//optimizer:optimizer_builder",
"//parser:parser_builder",
"//runtime",
],
)

java_library(
name = "optimizer_builder",
srcs = [
"CelOptimizer.java",
"CelOptimizerBuilder.java",
],
tags = [
],
deps = [
":ast_optimizer",
"//common",
"//common:compiler_common",
"@maven//:com_google_errorprone_error_prone_annotations",
],
)

java_library(
name = "optimizer_impl",
srcs = [
"CelOptimizerImpl.java",
],
tags = [
],
deps = [
":ast_optimizer",
":optimizer_builder",
"//bundle:cel",
"//common",
"//common:compiler_common",
"//common/navigation",
"@maven//:com_google_guava_guava",
],
)

java_library(
name = "ast_optimizer",
srcs = ["CelAstOptimizer.java"],
tags = [
],
deps = [
"//bundle:cel",
"//common",
"//common/navigation",
],
)
28 changes: 28 additions & 0 deletions optimizer/src/main/java/dev/cel/optimizer/CelAstOptimizer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package dev.cel.optimizer;

import dev.cel.bundle.Cel;
import dev.cel.common.CelAbstractSyntaxTree;
import dev.cel.common.navigation.CelNavigableAst;

/** Public interface for performing a single, custom optimization on an AST. */
public interface CelAstOptimizer {

/**
* Optimizes a single AST.
**/
CelAbstractSyntaxTree optimize(CelNavigableAst navigableAst, Cel cel);
}
38 changes: 38 additions & 0 deletions optimizer/src/main/java/dev/cel/optimizer/CelOptimizer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package dev.cel.optimizer;

import dev.cel.common.CelAbstractSyntaxTree;
import dev.cel.common.CelValidationException;

/** Public interface for optimizing an AST. */
public interface CelOptimizer {

/**
* Performs custom optimization of the provided AST.
*
* <p>This invokes all the AST optimizers present in this CelOptimizer instance via {@link
* CelOptimizerBuilder#addAstOptimizers} in their added order. Any exceptions thrown within the
* AST optimizer will be propagated to the caller and will abort the optimization process.
*
* <p>Note that the produced expression string from unparsing an optimized AST will likely not be
* equal to the original expression.
*
* @param ast A type-checked AST.
* @throws CelValidationException If the optimized AST fails to type-check after a single
* optimization pass.
*/
CelAbstractSyntaxTree optimize(CelAbstractSyntaxTree ast) throws CelValidationException;
}
34 changes: 34 additions & 0 deletions optimizer/src/main/java/dev/cel/optimizer/CelOptimizerBuilder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package dev.cel.optimizer;

import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.annotations.CheckReturnValue;

/** Interface for building an instance of CelOptimizer. */
public interface CelOptimizerBuilder {

/** Adds one or more optimizer to perform custom AST optimizations. */
@CanIgnoreReturnValue
CelOptimizerBuilder addAstOptimizers(CelAstOptimizer... astOptimizers);

/** Adds one or more optimizer to perform custom AST optimizations. */
@CanIgnoreReturnValue
CelOptimizerBuilder addAstOptimizers(Iterable<CelAstOptimizer> astOptimizers);

/** Build a new instance of the {@link CelOptimizer}. */
@CheckReturnValue
CelOptimizer build();
}
47 changes: 47 additions & 0 deletions optimizer/src/main/java/dev/cel/optimizer/CelOptimizerFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package dev.cel.optimizer;

import dev.cel.bundle.Cel;
import dev.cel.bundle.CelFactory;
import dev.cel.checker.CelChecker;
import dev.cel.compiler.CelCompiler;
import dev.cel.compiler.CelCompilerFactory;
import dev.cel.parser.CelParser;
import dev.cel.runtime.CelRuntime;

/** Factory class for constructing an {@link CelOptimizer} instance. */
public final class CelOptimizerFactory {

/** Create a new builder for constructing a {@link CelOptimizer} instance. */
public static CelOptimizerBuilder standardCelOptimizerBuilder(Cel cel) {
return CelOptimizerImpl.newBuilder(cel);
}

/** Create a new builder for constructing a {@link CelOptimizer} instance. */
public static CelOptimizerBuilder standardCelOptimizerBuilder(
CelCompiler celCompiler, CelRuntime celRuntime) {
return standardCelOptimizerBuilder(CelFactory.combine(celCompiler, celRuntime));
}

/** Create a new builder for constructing a {@link CelOptimizer} instance. */
public static CelOptimizerBuilder standardCelOptimizerBuilder(
CelParser celParser, CelChecker celChecker, CelRuntime celRuntime) {
return standardCelOptimizerBuilder(
CelCompilerFactory.combine(celParser, celChecker), celRuntime);
}

private CelOptimizerFactory() {}
}
84 changes: 84 additions & 0 deletions optimizer/src/main/java/dev/cel/optimizer/CelOptimizerImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package dev.cel.optimizer;

import static com.google.common.base.Preconditions.checkNotNull;

import com.google.common.collect.ImmutableSet;
import dev.cel.bundle.Cel;
import dev.cel.common.CelAbstractSyntaxTree;
import dev.cel.common.CelValidationException;
import dev.cel.common.navigation.CelNavigableAst;
import java.util.Arrays;

final class CelOptimizerImpl implements CelOptimizer {
private final Cel cel;
private final ImmutableSet<CelAstOptimizer> astOptimizers;

CelOptimizerImpl(Cel cel, ImmutableSet<CelAstOptimizer> astOptimizers) {
this.cel = cel;
this.astOptimizers = astOptimizers;
}

@Override
public CelAbstractSyntaxTree optimize(CelAbstractSyntaxTree ast) throws CelValidationException {
if (!ast.isChecked()) {
throw new IllegalArgumentException("AST must be type-checked.");
}

CelAbstractSyntaxTree optimizedAst = ast;
for (CelAstOptimizer optimizer : astOptimizers) {
CelNavigableAst navigableAst = CelNavigableAst.fromAst(ast);
optimizedAst = optimizer.optimize(navigableAst, cel);
optimizedAst = cel.check(optimizedAst).getAst();
}

return optimizedAst;
}

/** Create a new builder for constructing a {@link CelOptimizer} instance. */
static CelOptimizerImpl.Builder newBuilder(Cel cel) {
return new CelOptimizerImpl.Builder(cel);
}

/** Builder class for {@link CelOptimizerImpl}. */
static final class Builder implements CelOptimizerBuilder {
private final Cel cel;
private final ImmutableSet.Builder<CelAstOptimizer> astOptimizers;

private Builder(Cel cel) {
this.cel = cel;
this.astOptimizers = ImmutableSet.builder();
}

@Override
public CelOptimizerBuilder addAstOptimizers(CelAstOptimizer... astOptimizers) {
checkNotNull(astOptimizers);
return addAstOptimizers(Arrays.asList(astOptimizers));
}

@Override
public CelOptimizerBuilder addAstOptimizers(Iterable<CelAstOptimizer> astOptimizers) {
checkNotNull(astOptimizers);
this.astOptimizers.addAll(astOptimizers);
return this;
}

@Override
public CelOptimizer build() {
return new CelOptimizerImpl(cel, astOptimizers.build());
}
}
}
32 changes: 32 additions & 0 deletions optimizer/src/test/java/dev/cel/optimizer/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
load("//:testing.bzl", "junit4_test_suites")

package(default_applicable_licenses = ["//:license"])

java_library(
name = "tests",
testonly = 1,
srcs = glob(["*.java"]),
deps = [
"//:java_truth",
"//bundle:cel",
"//common",
"//common:compiler_common",
"//common/ast",
"//compiler",
"//optimizer",
"//optimizer:optimizer_builder",
"//optimizer:optimizer_impl",
"//parser",
"//runtime",
"@maven//:junit_junit",
],
)

junit4_test_suites(
name = "test_suites",
sizes = [
"small",
],
src_dir = "src/test/java",
deps = [":tests"],
)
Loading

0 comments on commit 73fb596

Please sign in to comment.